一、IO流
1.字节流:可以读取任意的文件
2.字节输出流:OutputStream
1)基本方法:
*void close()
关闭此输出流并释放与此流有关的所有系统资源。
*void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
*void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
*void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
*abstract void write(int b)
将指定的字节写入此输出流。
2)FileOutputStream extends OutputStream
*构造方法:
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的文件输出流
FileOutputStream(File file)
创建一个向指定File对象表示的文件中写入数据的输出文件流
参数:写入数据的目的
String name:目的地是一个文件的路径
File file:目的地是一个文件的文件
构造方法的作用
创建一个FileOutputStream对象
会根据构造方法中传递的文件/文件路径,创建一个空的文件
会把FileOutputStream对象指向创建好的文件
*字节输出流的的使用步骤
**创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
**调用FileOutputStream对象中的方法write,把数据写入到文件中
**释放资源(流会占用一定的内存,使用完毕要把内存清空,提高程序的效率
*文件写入原理
.write(int b) 会把十进制的整数转换为二进制的整数
任意的文本编辑器(记事本,notepad++)在打开文件的时候,都会查询编码表,把字节转换为字符表示
0-127:查询ASCII表
其他值:查询系统默认码表(中文系统是GBK)
*写入多个字节的方法
**void write(byte[] b)
**void write(byte[] b, int off, int len)
注意: 如果写的第一个字节是正数,那么现实的时候回查询ASCII表
如果写的第一个字节是负数,那第一个字节会和第二个字节(每一对字节)组成一个中文显示,查询GBK(中文系统默认码表)
*写入字符串的方法:
可使用String类中的方法把字符串转换为字节数组
Byte[] getBytes()
*数据的追加和换行-FileOutputStream特有的构造方法
**追加
FileOutputStream(String name,boolean append)
FileOutputStream(File file,boolean append)
参数append:追加写开关
**换行
write("/r/n".getBytes)
3.字节输入流:InputStream
1)基本方法:
*int read() 从输入流中读取数据的下一个字节
*int read(bytr[] b)从输入流中读取一定数量的字节,并将其存储在缓冲数组b中
*void close()关闭输入流并释放其关联的所有系统资源
2)FileInpuStream extends InputStream
*构造方法
FileInputStream(String name)
FileInpuStream(File file)
构造方法的作用:
创建一个人FileInputStream对象
会把FileInputStream对象制定构造方法中要读取的文件
*读取文件(固定写法)
while(len =file.read()!=-1){
Systrm.out.print((char)len);
}
*字节输入流一次读取多个字节的方法:int read(byte[] b)
必须明确的两件事情:
**方法的参数byte[]的作用
起到BUFFER作用,存储每次读取到的多个字节
数组的长度一般定义为1024或者是1024的整数倍
**方法返回值int是什么
返回读取到有效数据的长度,如果有效数据长度为0则返回-1
3)字节流的问题
使用字节流读取中文文件,每次只能读取一个字节,会得到乱码
1个中文->GBK:占用两个字节
->UTF-8:占用3个字节
4.字符输入流:Reader
1)基本方法:
*int read() 从字符输入流中读取数据的下一个字符
*int read(bytr[] b)从输入流中读取一定数量的字节,并将其存储在缓冲数组b中
*void close()关闭输入流并释放其关联的所有系统资源
2)FileReader
*构造方法
FileReader(String name)
FileReader(File file)
*读取文件(固定写法)
while(len =file.read()!=-1){
Systrm.out.print((char)len);
}
*缓冲读取多个字节的方法:int read(char[] b)
必须明确的两件事情:
**方法的参数byte[]的作用
起到BUFFER作用,存储每次读取到的多个字节
数组的长度一般定义为1024或者是1024的整数倍
**方法返回值int是什么
返回读取到有效数据的长度,如果有效数据长度为0则返回-1
5.字符输出流:Writer
1)基本方法
*void close()
关闭此输出流并释放与此流有关的所有系统资源。
*void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
*void write(char[] b)
将 b.length 个字节从指定的 char 数组写入此输出流。
*void write(char[] b, int off, int len)
将指定 char 数组中从偏移量 off 开始的 len 个字节写入此输出流。
*abstract void write(int b)
将指定的字节写入此输出流。
2)FileWriter
*构造方法
FileInputStream(String name)
FileInpuStream(File file)
*字符输出流的的使用步骤
**创建一个FileWriter对象,构造方法中传递写入数据的目的地
**调用FileWriter对象中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
**使用FileWriter中的flush,把内存缓冲区中的数据,刷新到文件中
**释放资源(流会占用一定的内存,使用完毕要把内存清空,提高程序的效率
注意:当调用void close()方法时,会强制输出内存缓冲区的内容
*close()和flush()的区别
-flush方法:刷新缓冲区,流对象可以继续使用
-close方法:先刷新缓冲区,然后通知系统释放资源,流对象不可以再被使用
*写入字符的其他方法:
-void write(char[] cbuf) 写入字符数组
-void write(char[] cbuf,int off,int len); 写入字符数组的一部分(off)开始,(len)长度
-void write(String str)
-void write(String str,int off int len); 写入字符串的一部分(off)开始,(len)长度
*字符流的续写和换行-和字节流一样
6.IO异常的处理
1)JDK7之前的处理
使用try...catch...final处理流中的异常--非常麻烦
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(path,true);
fileWriter.write(String str);
}catch(IOException e){
e.printStackTrace();
}finally{
if(fileWriter !=null){
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2)JDK7新特性-try(定义流对象){读取的代码}...catch...
以上的代码可以写为
try(fileWriter = new FileWriter(path,true);){
fileWriter.write(String str);
}catch(IOException e){
e.printStackTrace();
}
注意:在try后边增加一个(),在括号中可以定义流对象
那么这个流对象的作用域就在括号中,当代码执行结束后,会把流自动释放
所以不用写close()
3)JDK9新特性
try的前边可以直接定义流对象,在try后边的括号()中可以直接引入流对象(变量名)
在try代码执行完毕之后,流对象也可以释放掉,不用写finally和close;
注意:创建的资源必须是final修饰或者是有效final(不再次赋值)的
4)JDK9的使用场景
7.属性集-表示一个永久的属性集,它使用键值结构存储数据
1)Properties extend HashTable<k,v> implementd Map<k,v>
*表示了一个持久的属性集,可保存在流中或从流中加载,属性列表中的每一个值都是一个字符串
*是唯一一个与IO流结合的集合
**可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中储存
**可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
*Properties集合存储数据/取出数据
**Object setProperty(String key,String value) 调用Hashtable的方法Put
**String getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get方法
**Set<String> stringPropertyNames() 返回属性列表中的键集,相当于Map集合中的keySet方法
2)Properties集合中的store方法-将Properties集合中的数据放入硬盘中保存
*方法:
**void store(OutputStream out,String comments)
**void store(Writer writer,String comments)
**参数:
OutputStream out:字节输出流不能写入中文
Writer writer:字节输出流,可以写中文.
String comments:注释,用来解释保存文件是做什么用的(一般使用空字符串)
不能使用中文,会产生乱码,因为其默认为Unicode编码
*使用步骤:
创建一个Properties集合对象,添加数据
创建字节流/字符流输出对象,构造方法中绑定要输出的目的地
使用Properties集合中的方法store,把集合中的临时数据持久化写入到硬盘中存储
释放资源
3)Properties集合中的load方法-将文件中的键值对读取到集合中使用
*方法:
**void load(InputStream inStream)
**void load(Reader reader)
**参数:
Input Stream inStream:字节流输入,不能读取有中文的键值对
Reader reader:字符流输入,可以读取含有中文的键值对
*使用步骤:
创建一个Properties集合对象
使用Properties集合对象中的方法load读取保存键值对的文件
遍历Properties集合
*注意事项
存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
例: 键 值/键$值
存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
存储键值对的文件中,键与值默认都是字符串,不用再加""
二、缓冲、转换、序列化、打印流
注:都是包装流,并不是真正的输入输出流
问题:缓冲输入流如何提高效率?InputStream中的int read(byte[] bytes)是自己创建一个缓冲区
和BufferedInputStream有什么区别?其内存关系是怎么样的?
1.缓冲流
1)字节缓冲流
*BufferedOutputStream extends OutputStream
**继承自父类的方法:
-0void close()
关闭此输出流并释放与此流有关的所有系统资源。
-void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
-void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
-void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
-abstract void write(int b)
将指定的字节写入此输出流。
**构造方法:
-BufferedOutputStream(OutputStream out):
创建一个新的缓冲输出流,以将数据写入指定的低层输出流
-BufferedOutputStream(OutputStream out,int size)
创建一个新的缓冲输出流,并指定大小,以将数据写入指定的低层输出流
**使用步骤(重点)
-创建FileOutputStream对象,构造方法中绑定要输出的目的地
-创建BufferedOutputStream对象,构造方法中传递FileInput对象,提高FileOutputStream对象的效率
-使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
-使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
-释放资源(第四步可以省略)
*BufferedInputStream extends InputStream
**构造方法
-BufferedInputStream(InputStream in): 使用基本流创建一个缓冲字节输入流
-BufferedInputStream(InputStream in, int size): 使用基本流创建一个缓冲字节输入流, 设置缓冲区大小
2)字符缓冲流
*BufferedWriter extends Writer
**构造方法
-BufferedWriter(Writer out): 使用基本流创建一个缓冲字符输出流
-BufferedWriter(Writer out, int size): 使用基本流创建一个缓冲字符输出流, 设置缓冲区大小
**特有方法
-void newLine(): 写入一个换行符, 换行符自动根据当前系统确定
*BufferedWriter extends Writer
**构造方法
-BufferedReader(Reader in): 使用基本流创建一个缓冲字符输入流
-BufferedReader(Reader in, int size): 使用基本流创建一个缓冲字符输入流, 设置缓冲区大小
**特有方法
-String readLine(): 一次读一行字符串, "不包含换行符". 读到文件末尾返回null
2.转换流--防止读取乱码问题
1)字符编码和字符集
*字符编码和解码-一套自然语言和二进制数质检的对应规则
编码:字符(能看懂的)->字节(看不懂的)
解码:字节(看不懂的)->字符(看得懂的)
*字符集
包含编码表,是一个系统支持的所有字符的集合,一套字符集必须包含一套编码表
常用码表:ASCII字符集/GBK字符集/Unicod字符集(UTF8编码,UTF16编码,UTF32编码)
*常用字符集:
ISO-8859-1 没有中文的编码表
UTF-8:通用编码
GBK:中文系统默认编码表
*编码引出的问题:
当读取的编码和存储的编码不一致时,会引发乱码问题
2)转换流原理:
*使用字节流读取字节,根据默认(或给定)的码表转换为字符
*FileReader是InputStreamWriter的子类,它只可以使用系统默认的码表
3)输出转换流
*OutputStreamWriter类: 输出转换流. 字符流通往字节流的桥梁
**构造方法
-OutputStreamWriter(OutputStream out): 使用默认编码表创建转换流
-OutputStreamWriter(OutputStream out, String charsetName): 使用指定编码表创建转换流
charseName:"GBK","UTF-8","ISO-8859-1"
4)输入转换流
*InputStreamReader类: 输入转换流. 字节流通往字符流的桥梁
**构造方法
-InputStreamReader(InputStream in): 使用默认编码表创建转换流
-InputStreamReader(InputStream in,?String charsetName): 使用指定编码表创建转换流
3.序列化流(对象流)
1)序列化和反序列化
*对象的序列化:把对象以字节流的方式写入到文件中保存
*对象的反序列化:把文件中的对象使用字节流读取出来
注意:Serializable接口也叫标记型接口
当我们进行序列化的时候,就会检测类上是否有这个标记
如果实现了Serializable接口,就可以序列化和反序列化
如果未实现Serializable接口,则会抛出NotSerializableException
2)java.io.ObjectOutputStream类: 对象字节输出流
*构造方法
-ObjectOutputStream(OutputStream out)
*特有成员方法
-void writeObject(Object obj): 将对象写出
3)ObjectInputStream类: 对象字节输入流
*构造方法
-ObjectInputStream(InputStream in)
*特有成员方法
-Object readObject(): 读取对象
4)瞬态关键字-transient
*static关键字修饰的属性(成员变量)不能被序列化
*transient关键字修饰的属性也不能被序列化,但是不具备static的属性
5)【重要】InvalidClassExcption异常:原因和解决办法
*如果将对象序列化到文件中后,代码中的类发生了变化,那么反序列化会失败抛出InvalidClassException
**原因:编译期会把类文件(如Person)编译称为class,因为Person类实现了Serializeable接口,
会根据类的定义给Person.class文件添加一个序列号:serialVersionUID = -??????
当类被修改后,重新生成一个新的序列号
**解决方法:当定义一个可序列化的类时,人为添加一个serialVersionUID字段
该字段必须是(private) static final long serialVerionUID = 数字L;
4.打印流
1)PrintStream extens OutputStream 字节打印流
*构造方法
-PrintStream(File file): 创建字节打印流, 输出到一个文件
-PrintStream(OutputStream out): 创建字节打印流, 输出到一个字节输出流
-PrintStream(String fileName): 创建字节打印流, 输出到一个文件路径
*特点:
-只负责数据的输出,不负责数据的读取
-永远不会抛出IOException
-特有的方法:print和println方法
注意:如果使用继承自父类的write方法写数据,那么查看数据的手会查询编码表
如果使用特有的方法写数据,那么写的数据原样输出.
2)java.lang.System类:
*静态方法
static void setOut(PrintStream out): 设置System.out的输出目的地为参数的打印流
|
|