在开始整理文件读取和写入对象之前,先回顾一下文件读取和写入的内容:
传输过程中,传输数据的最基本单位是字符的流
通过 BufferedReader
读取文件内容:
public static void readFile() throws IOException { Path path = Paths.get("data.txt"); BufferedReader reader = Files.newBufferedReader(path); String lineContent = reader.readLine(); while (lineContent != null) { System.out.println(lineContent); lineContent = reader.readLine(); } reader.close(); }
BufferedReader
: 由 Reader
类扩展而来,提供通用的缓冲方式文本读取来提高效率,而且提供了很实用的 readLine()
方法
通过 BufferedWriter
向文件中写入:
public static void writeFile(String[] data) throws IOException { Path path = Paths.get("data.txt"); BufferedWriter writer = Files.newBufferedWriter(path); for (int i=0;i<data.length;i++) { writer.write(data[i]); writer.newLine(); } writer.close(); }
传输过程中,传输数据的最基本单位是字节的流
通过 BufferedInputStream
读取文件内容:
public static void readFile() throws IOException { FileInputStream file = new FileInputStream("data.txt"); BufferedInputStream reader = new BufferedInputStream(file); byte[] buff = new byte[MAX_SIZE]; while ((len = reader.read(buff)) != -1) { System.out.println(new String(buff, 0, len)); } reader.close(); file.close(); }
new String(byte bytes[], int offset, int length, String charsetName);
: 通过指定字符集对二进制数组进行编码,并转换成字符串形式。
通过 BufferedOutputStream
向文件中写入:
public void writeFile(String data) throws IOException { FileOutputStream file = new FileOutputStream("data.txt"); BufferedOutputStream writer = new BufferedOutputSream(file); writer.write(data.getBytes()); writer.close(); file.close(); }
BufferedInputStream
和 BufferedOutputStream
: 一种通过封装其它流来提高效率的流,所以使用前需要先实例化一个其它的流。
从本质上来讲,不管是读还是写数据,都是将二进制以字节为单位进行存取操作。字节流就是直接以二进制形式读取或写入文件内容,我们如果想要知道读取的内容,需要指定一种编码方式,写入时则需要转换成 Byte
类型。而字符流则自带了一种编码,所以读取和写入时不需要我们手动转换,而且基本的单位是以字符的大小为标准。
想要对对象进行读取和写入文件的操作,需要让该对象先实现一个接口 Serializable
Serializable
是 java.io
包中定义的、用于实现类的序列化操作而提供的一个语义级别的接口。Serializable
接口没有任何方法或者字段,只是用于标识可序列化的语义。实现了 Serializable
接口的类可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型,它可以被 ObjectOutputStream
转换为字节流,同时也可以通过 ObjectInputStream
再将其解析为对象。
public void readObject() throws IOException, ClassNotFoundException { FileInputStream file = new FileInputStream(new File("data.txt")); ObjectInputStream reader = new ObjectInputStream(file); YourClassName Cls = (YourClassName) reader.readObject(); file.close(); reader.close(); }
public void writeObject(YourClassName Data) throws IOException { FileOnputStream file = new FileOnputStream(new File("data.txt")); ObjectOnputStream writer = new ObjectOnputStream(file); writer.writeObject(Data); file.close(); reader.close(); }
public List readMulObject() throws IOException { List<Student> lst = new ArrayList<>(); FileInputStream file = new FileInputStream(new File("data.txt")); ObjectInputStream reader = new ObjectInputStream(file); while (true) { try { YourClassName Cls = (YourClassName) reader.readObject(); lst.add(Cls); } catch (EOFException e) { System.out.println("读取完成"); break; } } file.close(); reader.close(); return lst; }
public void writeFile(List<YourClassName> lst) throws IOException { FileOutputStream file = new FileOutputStream(new File("data.txt")); ObjectOutputStream writer = new ObjectOutputStream(file); for (YourClassName Cls : lst) { writer.writeObject(Cls); } writer.close(); }
这里有一个问题,在写入对象时,默认会从文件开头开始写入,这样会覆盖文件原本的内容。想在文件后部追加写入的话,需要 FileOutputStream file = new FileOutputStream(new File("data.txt"), 1)
但这样又会有一个问题:在每次打开文件时,程序会默认在写入信息之前加一个 ACED 0005
字段,但在读取的时候,会误认为它是对象的一部分,导致解析出错。这个问题我目前还没有发现完善的解决方案,现在采取的措施是,在写入文件前,先用 List
把内容全部取出,然后写入的信息全部加到 List
里,再把 List
一整个存入文件。