Java I/O 流详解
目录
1.FileOutputStream与FileInputStream
2.BufferedOutputStream与BufferedInputStream
3.ObjectOutputStream与ObjectOutputStream
4.DateInputStream与DateOutputStream
2.BufferedWriter与BufferedReader
3.OutputStreamWriter与InputStreamReader
前言:
java.io包官方对其表述是:
Provides for system input and output through data streams, serialization and the file system
可以将Java I/O 大分为两类,字符流和字节流,字符流处理的单元为2个字节的Unicode字符,而字节流处理单元为1个字节,字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点。
I/O体系的基本结构如下(详细结构下文说明):
字节流
字节输出流由抽象类 OutputStream 及其实现类构成,具体结构如下:
字节输入流由抽象类 InputStream 及其实现类构成,具体结构如下:
1.FileOutputStream与FileInputStream
用于将数据以字节流的方式读写,FileOutputStream用于写原始字节流,例如图像数据。如要编写字符流,请考虑使用 FileWriter,同样可以使用FileReader代替 FileInputStream。
示例代码:
public class Main {
public static void main(String[] args) {
File file = new File("src/test.txt");
/*
字节流的写出
*/
try (
FileOutputStream fileOutputStream = new FileOutputStream(file, false)//将append设置为true 表示每次再文件后添加数据
) {
String string = "你的名字";
byte[] bytes = string.getBytes();
fileOutputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
/*
字节流的读入
*/
try (
FileInputStream fileInputStream = new FileInputStream(file)
) {
/*int count = 0;//记录该字节流读取的字节数
while (fileInputStream.read() != -1) { //read操作类似于指针,逐次读取字节流中的字节,当无可读字节时,返回—1
count++;
}
System.out.println(count);//此处输出值为12,再uft-8,汉字使用3个字节编码*/
byte[] bytes = new byte[20];
int i = fileInputStream.read(bytes);//将字节流中的数据逐次写入bytes中,并返回总共读取的字节数
String string = new String(bytes);
System.out.println(string);
System.out.println(i);
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果如下:
2.BufferedOutputStream与BufferedInputStream
缓冲字节流,再流中间提供一个缓冲区,提高数据读取和写入的速度
示例代码:
public class Main {
public static void main(String[] args) {
File file=new File("src/test.txt");
StringBuilder stringBuilder=new StringBuilder();
for (int i=0;i<100000;i++){
stringBuilder.append("你难道没有见过江流奔涌的样子吗?\n");
}
String string=stringBuilder.toString();
byte[] bytes=string.getBytes();
/*
缓冲输出字节流,它是对输出字节流的包装
*/
try {
if(!file.exists()) file.createNewFile();
OutputStream outputStream=new FileOutputStream(file);
long date1=System.currentTimeMillis();
outputStream.write(bytes);
outputStream.flush();
long date2=System.currentTimeMillis();
System.out.println("输出字节流使用时间:"+(date2-date1));
BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(outputStream,1024);//设置缓冲区大小为1024个字节
long date3=System.currentTimeMillis();
bufferedOutputStream.write(bytes);
bufferedOutputStream.flush();
long date4=System.currentTimeMillis();
System.out.println("缓冲输出字节流使用时间:"+(date4-date3));
bufferedOutputStream.close();
outputStream.close();
}catch (Exception e){
e.printStackTrace();
}
/*
缓冲输入字节流,它是对输入字节流的包装
*/
try{
InputStream inputStream=new FileInputStream(file);
long date1=System.currentTimeMillis();
byte[] bytes1=new byte[10000000];
inputStream.read(bytes1);
long date2=System.currentTimeMillis();
System.out.println("输入字节流使用时间:"+(date2-date1));
String string1=new String(bytes1);
BufferedInputStream bufferedInputStream=new BufferedInputStream(inputStream,1024);
long date3=System.currentTimeMillis();
byte[] bytes2=new byte[10000000];
bufferedInputStream.read(bytes2);
long date4=System.currentTimeMillis();
System.out.println("缓冲输入字节流使用时间:"+(date4-date3));
bufferedInputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
运行结果:
可见,当数据量较大时,缓冲流可以提高读写效率
3.ObjectOutputStream与ObjectOutputStream
对象输出输入流,用于对象的序列化与反序列化,一个对象要想被序列化则必须实现Serializable 接口,如果要设置该对象中的某个属性是不可序列化的,则需使用 transient 关键字声明该属性是短暂的,对它的赋值将不会被序列化,序列化文件以xxx.ser后缀。
整个过程都是Java虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象
示例代码:
import java.io.*;
/**
* @Author: QianQian
* @CreateDate: 2019/11/30 17:17
*/
public class Main {
public static void main(String[] args) {
File file=new File("src/student1.ser");
Student student=new Student("康康",19);
student.setScore(100);
System.out.println(student.toString());
/*
对象的序列化
*/
try{
if(!file.exists()) file.createNewFile();
OutputStream outputStream=new FileOutputStream(file);
ObjectOutputStream objectOutputStream=new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(student);
objectOutputStream.close();
outputStream.close();
}catch (IOException e){
e.printStackTrace();
}
/*
对象的反序列化
*/
try{
InputStream inputStream=new FileInputStream(file);
ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
Student student1= (Student) objectInputStream.readObject();
System.out.println(student1.toString());
objectInputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
class Student implements Serializable{
private String name;
private int age;
private transient int score;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
运行结果:
4.DateInputStream与DateOutputStream
数据输入输出流可以将Java的基本类型写入到文件或读取,与机器本身的环境无关
示例代码:
public class Main {
public static void main(String[] args) {
File file=new File("src/test.txt");
try(
FileOutputStream fileOutputStream=new FileOutputStream(file);
DataOutputStream dataOutputStream=new DataOutputStream(fileOutputStream);
){
dataOutputStream.writeInt(23);
dataOutputStream.writeBoolean(true);
dataOutputStream.writeFloat(3.2312f);
dataOutputStream.writeUTF("hello world");
dataOutputStream.flush();
}catch (IOException e){
e.printStackTrace();
}
try(
FileInputStream fileInputStream=new FileInputStream(file);
DataInputStream dataInputStream=new DataInputStream(fileInputStream);
){
//要按照写入的顺序依次读取,否则会抛出异常
System.out.println(dataInputStream.readInt());
System.out.println(dataInputStream.readBoolean());
System.out.println(dataInputStream.readFloat());
System.out.println(dataInputStream.readUTF());
}catch (IOException e){
e.printStackTrace();
}
}
}
运行结果:
字符流
字符输出流是抽象类Writer及其实现类组成:
字符输入流是抽象类Reader及其实现类组成:
1.FiletWriter与FiletReader
此类方便读写字符类文件,以字符为单位进行读写,该类的构造函数默认字符编码和缓冲区大小都是可以接受的,如果要自己定义编码方式和缓冲区大小,则可通过OutputStreamWriter使用FileOutputStream构建一个FileWriter。
代码示例:
public class Main {
public static void main(String[] args) {
File file=new File("src/test.txt");
try(
FileWriter fileWriter=new FileWriter(file,false)
){
String string="你难道没有见过江流奔涌的样子吗?";
fileWriter.write(string);
}catch (IOException e){
e.printStackTrace();
}
try(
FileReader fileReader=new FileReader(file)
){
char[] chars=new char[100];
int len=fileReader.read(chars);
System.out.println(new String(chars,0,len));
}catch (IOException e){
e.printStackTrace();
}
}
}
2.BufferedWriter与BufferedReader
输入与输出的字符缓冲流,可以用以包装FileWriter和FileReader, 提高字符流的读写效率,提供了一个newLine()方法,它使用平台自己的系统属性line.separator定义的行分隔符概念。 并非所有平台都使用换行符('\ n')来终止行。 因此,调用此方法来终止每个输出行,因此优选直接写入换行符
示例代码:
public class Main {
public static void main(String[] args) {
File file=new File("src/test.txt");
try(
FileWriter fileWriter=new FileWriter(file,false);
BufferedWriter bufferedWriter=new BufferedWriter(fileWriter,1024)//指定缓冲区大小
){
String string="你难道没有见过江流奔涌的样子吗?";
bufferedWriter.write(string);
bufferedWriter.newLine();
bufferedWriter.write(string);
}catch (IOException e){
e.printStackTrace();
}
try(
FileReader fileReader=new FileReader(file);
BufferedReader bufferedReader=new BufferedReader(fileReader)
){
String string=null;
while((string=bufferedReader.readLine())!=null){//判断读取的一行是否为空
System.out.println(string);
}
}catch (IOException e){
e.printStackTrace();
}
}
}
运行结果:
3.OutputStreamWriter与InputStreamReader
这两个个类是字节流转化为字符流的桥梁,在转换时可以指定字符流的编码形式,否则使用平台的默认字符集
代码示例:
public class Main {
public static void main(String[] args) {
File file=new File("src/test.txt");
String string="你难道没有见过江流奔涌的样子吗?";
try(
FileOutputStream fileOutputStream=new FileOutputStream(file,false);
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(fileOutputStream,"gbk");//设置输出字符流的编码方式为GBK
BufferedWriter bufferedWriter=new BufferedWriter(outputStreamWriter)
){
bufferedWriter.write(string);
}catch (IOException e){
e.printStackTrace();
}
try(
FileInputStream fileInputStream=new FileInputStream(file);
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream,"gbk");//设置输入字符流的编码方式也为GBK,否则读取乱码
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
){
System.out.println(bufferedReader.readLine());
}catch (IOException e){
e.printStackTrace();
}
}
}
运行结果:(因为IDEA的默认编码方式为UTF-8,所以文件里的数据显示乱码,但如果同样使用GBK的方式读取数据,那么数据依然可以正常显示)
上一篇: QT5 常用控件