在开始整理文件读取和写入对象之前,先回顾一下文件读取和写入的内容:
字符流与字节流
1. 字符流
传输过程中,传输数据的最基本单位是字符的流
通过 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();
}
2. 字节流
传输过程中,传输数据的最基本单位是字节的流
通过 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
: 一种通过封装其它流来提高效率的流,所以使用前需要先实例化一个其它的流。
3. 字符流和字节流的区别
从本质上来讲,不管是读还是写数据,都是将二进制以字节为单位进行存取操作。字节流就是直接以二进制形式读取或写入文件内容,我们如果想要知道读取的内容,需要指定一种编码方式,写入时则需要转换成 Byte
类型。而字符流则自带了一种编码,所以读取和写入时不需要我们手动转换,而且基本的单位是以字符的大小为标准。
对象的读取和写入
想要对对象进行读取和写入文件的操作,需要让该对象先实现一个接口 Serializable
Serializable
是 java.io
包中定义的、用于实现类的序列化操作而提供的一个语义级别的接口。Serializable
接口没有任何方法或者字段,只是用于标识可序列化的语义。实现了 Serializable
接口的类可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型,它可以被 ObjectOutputStream
转换为字节流,同时也可以通过 ObjectInputStream
再将其解析为对象。
1. 读取一个对象
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();
}
2. 写入一个对象
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();
}
3. 读取多个对象
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;
}
4. 写入多个对象
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
一整个存入文件。