文章目录
File文件类
IO流体系
FileInputStream类
构造方法:
FileInputStream(File file); //通过File文件对象创建FileInputStream。 FileInputStream(String name); //通过通过文件路径name创建FileInputStream。 FileInputStream(FileDescriptor fdObj); //通过文件描述符fdObj创建
使用流程:
FileInputStream fileInputStream = null; byte arr[] = new byte[3]; int lastone = 0; try { fileInputStream = new FileInputStream("D:\\train\\lxl2.txt"); while ((lastone = fileInputStream.read(arr)) != -1) { System.out.print(new String(arr,0,lastone)); } } catch (IOException e) { if (e instanceof FileNotFoundException) { System.out.println("创建文件输入流对象失败~"); } else { System.out.println("读取文件内容失败~"); } } finally { try {//文件流使用后最后应该关闭 fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } }
FileOutputStream类
构造方法:
//构造方法: FileOutputStream(File file) FileOutputStream(File file, boolean append) FileOutputStream(FileDescriptor fdObj) FileOutputStream(String name) FileOutputStream(String name, boolean append) //若append为true,字节将被写入文件的末尾而不是开头
使用流程:
String text = "LXL,THE GOR FOREVER~"; try { fileOutputStream = new FileOutputStream(pathname); //fileOutputStream.write('L');写入单个字符 fileOutputStream.write(text.getBytes()); //text.getBytes获取对应数组 fileOutputStream.flush();//可省略,close()调用时内部调用flush() } catch (IOException e) { e.printStackTrace(); } finally { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } }
FileReader类
构造方法:
FileReader(File file); //通过文件对象创建 FileReader(String fileName); //通过文件路径创建
注意事项:
- FileReader是InputStreamReader类的子类,其底层借助父类完成字节转字符。
- FileReader类的构造函数调用父类的独参数构造,默认指定字符编码和默认字节缓冲区大小,无法更改。
FileWriter类
构造方法:
FileWriter(File file); //通过File文件对象创建 FileWriter(String fileNam); //通过文件路径创建 FileWriter(String fileName,true); //流指针在文件末尾的FileWriter对象 //若append为true,字节将被写入文件的末尾而不是开头
注意事项:
- FileWriter是InputStreamReader类的子类,其底层借助父类完成字节转字符。
- FileWriter类的构造函数调用父类的独参数构造,默认指定字符编码和默认字节缓冲区大小,无法更改。
- FIleWriter具有缓冲区,不能保证缓冲区内容全被写出,需调用其flush(),或调用该流的close()强制写出。
转换流
InputStreamReader类概述:
- InputStreamReader是Reader子类,可将InputStream(字节流)包装成Reader(字符流)
- 用指定的字符集将读取的字节解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
- 处理纯文本文件时字符流的处理效率高,且有效解决编码问题,建议将字节流转为字符流。
- InputStreamReader可能会导致从底层字节输入流读取比当前操作所需的更多字节。目的是使字节有效地转换为字符。
- 为了最大的效率,可考虑在BufferedReader中包装一个InputStreamReader。
InputStreamReader构造器:
InputStreamReader(InputStream in); //创建一个使用默认字符集的字符流。 InputStreamReader(InputStream in, String charsetName); //创建一个指定字符集的字符 【能够处理中文乱码问题】
InputStreamReader使用场景:
/* * 读取数据gbk.txt * 产生中文乱码: * 文件编码使用的是gbk;程序读取码表使用的是utf-8 * 我们使用转换流对象:InputStreamReader */ InputStreamReader isr = new InputStreamReader(new FileInputStream("day11_io/src/gbk.txt"),"gbk"); //使用gbk编码将读取的字节转换为对应的正确字符!!!
OutputStreamWriter类概述:
- OutputStreamWriter是Writer子类,可将OutputStream(字节流)包装成Writer(字符流)
- 使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
- OutputStreamWriter每调用write方法都会使编码转换器被调用,所得到的字节在写入底层输出流之前累积在缓冲区中。
- 为了最大的效率,可考虑在BufferedWriter中包装一个OutputStreamWriter,避免频繁的转换器调用
OutputStreamWriter构造器:
InputStreamReader(InputStream in); //创建一个使用默认字符集的字符流。 InputStreamReader(InputStream in, String charsetName); //创建一个指定字符集的字符 【能够处理中文乱码问题】 InputStreamReader(InputStream in, CharsetDecoder dec); //创建一个使用给定字符集解码器的InputStreamReader
OutputStreamWriter使用场景:
/* * 文件默认给定的码表是gbk,idea使用的是utf-8. 将代码写出数据的码表指定为gbk即可 */ OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day11_io/src/gbk.txt"),"gbk") //使用gbk编码将需要写出的字符转换为正确的字节后再写出!!!
包装(Buffered)流
概述:
- 节点流可以从一个特定数据源(文件、数组、字符串等)读写数据,如FileReader等。
- 包装流是"连接"已存在的流(节点流/处理流)之上,为程序提供更强大的读写功能,如BufferedReader等。
- 处理流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源连接。
- 处理流性能高,增加缓冲的方式提高效率;处理流操作便捷,提供一系列方法来操作大批数据,使用更加灵活方便。
- 包装流的写入模式遵循于底层的节点流的写入模式(是否追加)。
字节包装流:
BufferedOutputStream
,缓冲字节输出流。BufferedInputStream
,缓冲字节输入流。- 字节包装流的方法基本与顶级父抽象类一致。
字符包装流:
BufferedWriter
,缓冲字符输出流。BufferedReader
,缓冲字符输入流。- 字符包装流新增行操作,如BufferedReader中有
readLine()
,BufferedWriter中有newLine()
,其他方法基本与顶级父抽象类一致。注意事项:缓冲写出流中的write操作都是将内容写入其对象的byte[]缓冲数组中,当buffer缓冲容量到达上限时才会触发磁盘写出,当写出内容大小不足自动触发磁盘写出,需手动调用
flush
方法。
序列化流
概述:Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。内存的数据到硬盘就是序列化!硬盘的数据到内存就是反序列化!
序列化注意事项:
序列化在保存数据时,能保存数据的值和数据类型。
反序列化是值恢复数据时,能恢复数据的值和数据类型。
需使某个对象支持序列化机制,必须使其类是可序列化,即该类必须实现
Serializable
或Externalizable
接口(推荐使用前者)。序列化后保存的文本格式是按照其固定格式
xx.dat
保存。读写顺序一致
序列化类中建议添加SerialVersionUID以提高版本兼容性,如
public static final long SerialVersionUID = 1L;
,该UID可设置IDEA配置(Editor->Inspections)来快速生成。序列化对象时,默认将其所有属性序列化,static与transient修饰除外。
序列化对象时,要求其所有属性类型也都实现序列化接口
序列化可继承,父类实现序列化接口,子类默认实现序列化
ObjectOutputStream类
概述:java.io.ObjectOutputStream类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。若类没有实现Serializable接口,会出现异常:NotSerializableException
构造器:
public ObjectOutputStream(OutputStream out); //创建一个指定OutputStream的ObjectOutputStream。
使用:
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/io/student.dat")); oos.writeObject(student);
ObjectInputStream类
概述:ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
构造器:
public ObjectInputStream(InputStream in); //创建一个指定InputStream的ObjectInputStream。
使用:
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/io/student.txt")); Student s = (Student) ois.readObject();
若读取未知数量的对象dat文件解决方案:
- 第一种方案:可使用字节输入流的available方法,而不是对象序列化流的available方法,经测试得知对象序列化流的对象使用available得到的结果一直是0,而构造它的字节输入流使用available方法,得到的是>0的数。
- 第二种方案:将所有对象先用集合打包好再写入,不管集合存有多少个对象下次读取时都只需读取一次得到集合再遍历即可,无需判断结尾。
- 第三种方案:在将对象写入完成后末尾再写入一个null,下次读取时则判断读取对象是否为null,若为null则代表对象已经读取完毕。
打印流
概述:
- java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。
- 打印流有:
PrintStream
和PrintWriter
System.setOut(new PrintStream(paht));
设置System打印位置
PrintStream:
概述:继承于FilterOutputStream,实现Appendable,默认显示位置是显示器。
构造方法:
PrintStream(File file); //使用指定的文件创建一个新的打印流,而不需要自动换行。 PrintStream(String fileName); //使用指定的文件名创建新的打印流,无需自动换行。 PrintStream(String fileName, String csn); //创建一个新的打印流,不需要自动换行,具有指定的文件名和字符集。
PrintWriter:
概述:继承于Writer,默认显示位置是显示器
构造方法:
PrintWriter(File file); //使用指定的文件创建一个新的PrintWriter,而不需要自动换行。 PrintWriter(String fileName) //使用指定的文件名创建一个新的PrintWriter,而不需要自动换行。 PrintWriter(String fileName, String csn) //使用指定的文件名和字符集创建一个新的PrintWriter,而不需要自动换行。
Properties类
概述:
Properties类是Hashtable的子类,用于读取配置文件。
专门用于读写配置文件的集合类,配置文件格式:键 = 值。
键值对不需要有空格,值不需要用引号括起,默认类型是String。
常用方法:
void load(InputStream inStream); //从输入字节流读取属性列表(键和元素对) void list(PrintStream/PrintWriter out); //将此属性列表打印到指定的输出流 String getProperty(String key); //使用此属性列表中指定的键搜索属性。 Object setProperty(String key, String value); //添加或设置键值对,底层调用Hashtable方法put void store(Writer writer, String comments) //将此属性列表对写入此Properties表文件中,以适合使用load(Reader)格式读 void store(OutputStream out, String comments); //将此属性列表写入此Properties表文件中,以适合于使用load(InputStream)格式读
使用流程:
//使用java.util.Properties类的load(InputStream in)方法加载properties文件 String path = "D:\\a.properties" Properties ties = new Properties();//创建Properties对象 ties.load(new FIleReader(pathname));//加载配置文件信息到对象中 ties.list(System.out);
//使用class变量的getResourceAsStream()方法,注意getResourceAsStream()读取路径是与本类的同一包下 Properties prop = new Properties(); InputStream is = PropertiesUtil.class .getResourceAsStream("/com/util/prop.properties"); prop.load(is);
//使用class.getClassLoader()所得到的java.lang.ClassLoader的getResourceAsStream()方法getResourceAsStream(name)方法的参数必须是包路径+文件名+.后缀(默认从模块的src目录查找),否则会报空指针异常 Properties prop = new Properties(); InputStream is =PropertiesUtil.class.getClassLoader(). getResourceAsStream("com/util/prop.properties"); prop.load(is);
//使用java.lang.ClassLoader类的getSystemResourceAsStream()静态方法getSystemResourceAsStream()方法的参数格式也是有固定要求的(默认从模块的src目录查找) Properties prop = new Properties(); InputStream is = ClassLoader .getSystemResourceAsStream("com/util/prop.properties"); prop.load(is);
//使用java.util.ResourceBundle类的getBundle()方法,注意:这个getBundle()方法的参数只能写成包路径+properties文件名(默认从模块的src目录查找),否则将抛异常 ResourceBundle rb = ResourceBundle.getBundle("com/util/prop"); password = rb.getString("password");
IO流资源处理方式
JDK7中:将关闭流资源的代码写在finally语句体中,需要将流对象提到try-catch-finally的外部
JDK8中:
try ( FileWriter fw = new FileWriter("day11_io/src/fw.txt"); //意味着后面不用写finally,try后括号中创建流对象 //try-catch执行完后资源会自动关闭 ) { fw.write("Hello,Everyone"); } catch (IOException e) { e.printStackTrace(); }