目录
1.字符流的简介
2.字符的编码与解码
3.字符流读写操作
1.字符流写入
2.字符流复制文件
4.FileWriter&FileReader
5.缓冲区高效读写
6.序列化与反序列化
1.字符流的简介
在Java中,字符流是用于处理字符数据的输入输出流。它是以字符为单位进行处理,而不是字节。字符流主要用于处理文本文件,可以直接读取和写入字符数据。
Java提供了两种字符流:字符输入流和字符输出流。
字符输入流:
- FileReader:用于读取字符数据的输入流。它继承自Reader类,可以读取字符文件的内容。
- BufferedReader:用于读取字符数据的缓冲输入流。它继承自Reader类,可以提供更高效的字符读取操作。
字符输出流:
- FileWriter:用于写入字符数据的输出流。它继承自Writer类,可以将字符数据写入文件。
- BufferedWriter:用于写入字符数据的缓冲输出流。它继承自Writer类,可以提供更高效的字符写入操作。
使用字符流进行读写操作的一般步骤如下:
- 创建字符输入流或者字符输出流对象,参数为要读取或写入的文件。
- 使用字符输入流或者字符输出流的相应方法进行读取或写入操作。
- 关闭字符流。
2.字符的编码与解码
字符分为GBK格式和UTF-8格式,当我们想用GBK格式编码的时候就需要用GBK格式进行解码,UTF-8格式同理
//GBK格式
byte[] gbk = "hello java".getByte("GBK");
System.out.println(new String(gbk,"GBK"));
//UTF-8格式
byte[] utf = "hello java".getByte("UTF-8");
System.out.println(new String(utf,"UTF-8"));
3.字符流读写操作
1.字符流写入
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./test.txt"));
osw.write("hello world");
osw.close();
InputStreamReader isr = new InputStreamReader(new InputStreamRead("./test.txt"));
int ch;
while((ch = isr.read()) != -1){
System.out.println((char)ch);
}
isr.close();
以上代码是用字符流进行文件的写入和读取操作。
首先,代码创建了一个OutputStreamWriter对象osw,它使用FileOutputStream来创建文件输出流。这意味着我们将要写入的数据将被写入到test.txt文件中。
然后,使用osw的write方法将字符串"hello world"写入到输出流中,这个字符串将会被写入到test.txt文件中。
最后,调用osw的close方法来关闭输出流。
接下来,代码创建了一个InputStreamReader对象isr,它使用FileInputStream来创建文件输入流。这意味着我们将从test.txt文件中读取数据。
然后,使用isr的read方法读取文件中的字符数据。read方法返回的是读取到的字符的Unicode编码。在while循环中,将读取到的字符强制转换为char类型,并打印出来。
最后,调用isr的close方法来关闭输入流。
总结起来,以上代码的执行过程如下:
- 创建一个字符输出流,将字符串"hello world"写入到文件test.txt中。
- 创建一个字符输入流,从文件test.txt中读取字符数据,并将其打印出来。
- 关闭字符输出流和字符输入流。
注意事项:
- 在使用字符流进行读写操作时,需要进行异常处理,确保流的正确关闭。
- 运行以上代码前,需要确保test.txt文件不存在或者为空,否则将会被覆盖。
2.字符流复制文件
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./newtest.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("./test.txt"));
int len;
char[] ch = new char[1024];
while((len = isr.read(ch)) != -1){
osw.write(ch,0,len);
osw.flush();
}
osw.close();
isr.close();
以上代码是使用字符流进行文件的复制操作。
首先,代码创建了一个OutputStreamWriter对象osw,它使用FileOutputStream来创建文件输出流,文件名为newtest.txt。这意味着我们将要将数据写入到newtest.txt文件中。
接着,代码创建了一个InputStreamReader对象isr,它使用FileInputStream来创建文件输入流,文件名为test.txt。这意味着我们将从test.txt文件中读取数据。
然后,代码使用一个字符数组ch来缓存从文件输入流中读取的字符数据。len表示每次从输入流中读取的字符数。
在while循环中,通过isr的read方法将字符数据读取到ch数组中,并将实际读取的字符数赋值给len。当读取到文件末尾时,read方法将返回-1,循环结束。
然后,通过osw的write方法将ch数组中的字符数据写入到输出流中。这样,我们就实现了从输入流中读取数据,并将数据写入到输出流中,即完成了文件的复制操作。
注意,在每次写入数据后,通过osw的flush方法将缓冲区中的数据强制刷新到文件中,确保数据能够被及时写入。
最后,调用osw和isr的close方法关闭输出流和输入流。
总结起来,以上代码的执行过程如下:
- 创建一个字符输出流,将数据写入到newtest.txt文件中。
- 创建一个字符输入流,从test.txt文件中读取数据。
- 循环读取输入流中的字符数据,并将其写入到输出流中,实现文件的复制。
- 关闭字符输出流和字符输入流。
注意事项:
- 在使用字符流进行读写操作时,需要进行异常处理,确保流的正确关闭。
- 运行以上代码前,需要确保test.txt文件存在且有内容,否则将无法复制数据到newtest.txt文件中。
4.FileWriter&FileReader
FileWriter
和 FileReader
是 Java IO 包中用于文件的读写操作的类。
FileWriter
是一个字符输出流,用于将字符数据写入文件。它继承自 Writer
类,可以使用 write()
方法将字符写入文件。如果文件不存在,FileWriter
会自动创建文件;如果文件已存在,则会覆盖原有内容。
FileReader
是一个字符输入流,用于从文件中读取字符数据。它继承自 Reader
类,可以使用 read()
方法来读取文件中的字符。如果文件不存在或无法读取,FileReader
会抛出 FileNotFoundException
。
这两个类都是以字符为单位进行读写操作,适用于处理文本文件。它们通常与字符数组配合使用,可以一次读取或写入多个字符。
需要注意的是,FileWriter
和 FileReader
在读写文件时,并不会进行字符编码的转换。如果需要处理不同字符编码的文件,可以使用 InputStreamReader
和 OutputStreamWriter
来进行字符编码的转换操作。
FileReader fr = new FileReader("./test.txt");
FileWriter fw = new FileWriter("./newtest.txt");
int len;
char[] chars = new char[1024];
while((len = fr.read(chars)) != -1){
fw.write(chars,0,len);
}
fr.close();
fw.close();
这段代码使用 FileReader
和 FileWriter
来实现文件的读取和写入。
首先,创建一个 FileReader
对象 fr
,并指定读取的文件路径为 "./test.txt"。 然后,创建一个 FileWriter
对象 fw
,并指定写入的文件路径为 "./new.txt"。
接下来,通过一个循环,不断从 fr
读取字符,将读取的字符存入一个字符数组 chars
中,并将读取的字符个数赋值给 len
。 如果 len
不等于 -1,说明还有未读取的字符,将 chars
数组中的内容通过 fw
写入到指定文件中。这里使用 write(char[] cbuf, int off, int len)
方法来写入指定长度的字符数组。
最后,关闭 fr
和 fw
,释放资源。
这段代码的作用是将 "./test.txt" 文件中的内容复制到 "./new.txt" 文件中。
5.缓冲区高效读写
BufferReader br = new BufferReader("./test.txt");
BufferWriter bw = new BufferWriter("./newtest.txt");
int len;
char[] ch = new char[1024];
while((len = br.read(ch)) != -1){
bw.write(ch,0,len);
}
br.close();
bw.close();
代码中的 BufferedReader
和 BufferedWriter
是 Java IO 包中的缓冲字符流类,它们提供了对字符数据的缓冲读写功能,可以提高读写效率。
BufferedReader
是字符输入流,用于读取字符数据。它继承自 Reader
类,可以使用 read()
方法来读取文件中的字符。与 FileReader
不同的是,BufferedReader
会将数据缓存在内存中,以提高读取的效率。
BufferedWriter
是字符输出流,用于写入字符数据。它继承自 Writer
类,可以使用 write()
方法将字符写入文件。与 FileWriter
不同的是,BufferedWriter
会将数据缓存在内存中,以提高写入的效率。
在代码中,首先创建了一个 BufferedReader
对象,用于读取名为 "test.txt" 的文件。然后创建了一个 BufferedWriter
对象,用于写入名为 "newtest.txt" 的文件。
接下来,通过一个循环,使用 read()
方法从输入流中读取字符数据,并将其存储在字符数组 ch
中。然后使用 write()
方法将字符数组中的数据写入输出流。
循环会一直执行直到 read()
方法返回 -1,表示文件已读取完毕。最后,关闭输入流和输出流,释放资源。
使用 BufferedReader
和 BufferedWriter
可以提高读写效率,因为它们会将数据缓存起来,减少了对文件的实际读写次数。
缓冲区特有的方法
BufferReader br = new BufferReader("./test.txt");
BufferWriter bw = new BufferWriter("./newtest.txt");
String line;
while((line = br.readLine()) != null){
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
代码中的 BufferedReader
和 BufferedWriter
是 Java IO 包中的缓冲字符流类,它们提供了对字符数据的缓冲读写功能,可以提高读写效率。
BufferedReader
是字符输入流,用于读取字符数据。它继承自 Reader
类,可以使用 readLine()
方法逐行读取文件中的字符数据。与 FileReader
不同的是,BufferedReader
会将数据缓存在内存中,以提高读取的效率。
BufferedWriter
是字符输出流,用于写入字符数据。它继承自 Writer
类,可以使用 write()
方法将字符写入文件。与 FileWriter
不同的是,BufferedWriter
会将数据缓存在内存中,以提高写入的效率。
在代码中,首先创建了一个 BufferedReader
对象,用于读取名为 "test.txt" 的文件。然后创建了一个 BufferedWriter
对象,用于写入名为 "newtest.txt" 的文件。
接下来,通过一个循环,使用 readLine()
方法从输入流中逐行读取文本数据,并将每行数据存储在变量 line
中。然后使用 write()
方法将每行数据写入输出流,并调用 newLine()
方法插入换行符。最后,使用 flush()
方法将缓冲区的数据刷新到文件中。
循环会一直执行直到 readLine()
方法返回 null,表示文件已读取完毕。最后,关闭输入流和输出流,释放资源。
使用 BufferedReader
和 BufferedWriter
可以提高读写效率,因为它们会将数据缓存起来,减少了对文件的实际读写次数。同时,使用 readLine()
可以逐行读取文本数据,方便处理文本文件的内容。
6.序列化与反序列化
序列化和反序列化是指将对象转换成字节流的过程,以便在需要时可以将字节流重新转换为对象。序列化可以用于对象的持久化存储、网络传输等场景。
在序列化过程中,对象的状态信息(即对象的数据)被转换为字节流,可以通过将字节流写入文件或通过网络传输来保存。反序列化过程恢复字节流,将其转换为原始对象。
序列化和反序列化可以用于不同的编程语言之间的对象传输,因为字节流是一种通用的数据格式。
在Java中,可以使用Serializable接口将对象标记为可序列化的,然后使用ObjectOutputStream将对象序列化为字节流,使用ObjectInputStream将字节流反序列化为对象。
1.定义一个学生信息类
public class Student extends Serializable {
private String name;
private String sex;
private int age;
private float score;
public Student(String name, String sex, int age, float score) {
this.name = name;
this.sex = sex;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public int getAge() {
return age;
}
public float getScore() {
return score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
2.序列化对象
public class Serializable {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./test.txt"));
Student student = (Student)ois.readObject();
System.out.println(student.getName());
System.out.println(student.getSex());
System.out.println(student.getAge());
System.out.println(student.getScore());
ois.close();
}
}
这段代码实现了反序列化操作,读取保存在文件中的序列化对象并将其恢复为原始的Java对象。
首先,创建了一个ObjectInputStream对象ois,并通过它的构造方法将文件"./test.txt"与该ObjectInputStream关联起来。
接下来,通过ois调用readObject()方法,从文件中读取对象,并将其类型转换为Student对象。这里假设文件中保存的是一个Student对象,并且已经进行了序列化操作。
然后,通过Student对象的getter方法,获取Student对象中的各个属性值,并将其输出到控制台。
最后,通过ois调用close()方法关闭ObjectInputStream流,释放资源。
需要注意的是,如果文件中保存的对象类型与读取时转换的类型不匹配,会抛出ClassCastException异常。另外,如果文件中没有保存任何对象或文件不存在,会抛出FileNotFoundException异常。如果文件中保存的是非序列化的对象,会抛出InvalidClassException异常。
另外,代码中的Student类需要实现Serializable接口,以便进行序列化和反序列化操作。在Student类中,需要注意成员变量的访问修饰符为private,同时提供公共的getter和setter方法,以便在序列化和反序列化过程中访问和修改对象的属性值。
3.定义测试类
public class Ts {
public static void main(String[] args) throws IOException {
FileWriter();
Student newStu = FileReader();
System.out.println(newStu);
}
/**
* 读取学生信息
* @throws FileNotFoundException
*/
public static Student FileReader() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("./test.txt"));
String message = br.readLine();
String[] sp = message.split(",");
br.close();
return new Student(sp[0],sp[1],Integer.parseInt(sp[2]),Integer.parseInt(sp[3]));
}
/**
* 写入学生信息
* @throws IOException
*/
public static void FileWriter() throws IOException {
Student student = new Student("小李","女",18,98);
BufferedWriter bw = new BufferedWriter(new FileWriter("./test.txt"));
String message = student.getName() + "##" + student.getSex() + "##" +student.getAge() + "##" + student.getScore();
bw.write(message);
bw.close();
}
}
这段代码实现了文件的读写操作,用于存储和读取学生对象的信息。
首先,创建了一个名为FileWriter()的方法,在该方法中创建了一个Student对象并赋值。然后,通过BufferedWriter类将Student对象的信息以特定的格式写入到文件"./test.txt"中。以"##"分隔不同属性值,并使用换行符分隔不同学生对象的信息。最后,通过bw调用close()方法关闭BufferedWriter流,释放资源。
接下来,创建了一个名为FileReader()的方法,在该方法中创建了一个BufferedReader对象,并通过其构造方法将文件"./test.txt"与该BufferedReader关联起来。然后,通过br调用readLine()方法一次读取一行数据,将其保存在字符串变量message中。
接着,通过split()方法将message字符串按照逗号分隔成一个字符串数组sp,数组中的每个元素对应一个学生对象的属性值。
然后,通过返回一个新的Student对象,将数组sp中的各个值赋给Student对象的相应属性。其中,通过Integer.parseInt()方法将字符串转换为整数类型。
最后,通过br调用close()方法关闭BufferedReader流,释放资源。
在main()方法中,首先调用FileWriter()方法将学生对象的信息写入文件。然后,调用FileReader()方法读取文件中的学生信息,并将返回的Student对象赋给newStu。最后,通过System.out.println输出newStu对象的信息。
需要注意的是,在写入和读取文件时,需要确保文件的路径和名称正确,并注意处理可能出现的异常情况,如文件不存在或写入失败等。此外,代码中的Student类需要与之前的例子中的Student类一致,包括属性和getter、setter方法的定义。
运行结果:
显示数组索引异常
我们需要把
private static final long serialVersionUID = -5116101128118950844L;
添加到Student类中,就不会出现异常了