什么是流
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象,即数据在两设备间的传输称为流。
流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作
流的种类
【注】一个IO流可以即是输入流又是字节流又或是以其他方式分类的流类型,是不冲突的。比如FileInputStream,它既是输入流又是字节流还是文件节点流
根据流向划分
输入流和输出流,注意这是相对而言的
根据传输数据单位划分
- 字节流:数据流中最小的数据单元是字节
- 字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节(无论中文还是英文都是两个字节)
根据功能划分
- 节点流:可以从或向一个特定的地方(节点)读写数据,直接连接数据源。如最常见的是文件的FileReader,还可以是数组、管道、字符串,关键字分别为ByteArray/CharArray,Piped,String
- 处理流(包装流):并不直接连接数据源,是对一个已存在的流的连接和封装,是一种典型的装饰器设计模式,使用处理流主要是为了更方便的执行输入输出工作,如PrintStream,输出功能很强大,又如BufferedReader提供缓存机制,推荐输出时都使用处理流包装
特别的流
- 转换流:转换流只有字节流转换为字符流,因为字符流使用起来更方便,我们只会向更方便使用的方向转化。如:InputStreamReader与OutputStreamWriter。
- 缓冲流:有关键字Buffered,也是一种处理流,为其包装的流增加了缓存功能,提高了输入输出的效率,增加缓冲功能后需要使用flush()才能将缓冲区中内容写入到实际的物理节点。但是,在现在版本的Java中,只需记得关闭输出流(调用close()方法),就会自动执行输出流的flush()方法,可以保证将缓冲区中内容写入。
- 对象流:有关键字Object,主要用于将目标对象保存到磁盘中或允许在网络中直接传输对象时使用(对象序列化)
注:程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资源。如果不关闭该资源,那么磁盘的文件将一直被程序引用着,不能删除也不能更改。所以应该手动调用 close() 方法关闭流资源
io流的分类
用io流操作文件输入输出
1、字节流操作文件,进行文件的读取写入
public class ByteStream {
public static void main(String[] args) {
// 1.实例化文件对象
File inFile=new File("g:/test.txt");
File outFile=new File("g:/test1.txt");
// 2.实例化输入输出流对象
FileInputStream inputStream;
FileOutputStream outputStream;
try {
inputStream = new FileInputStream(inFile);
outputStream = new FileOutputStream(outFile);
// 3.创建字节集对象
byte[] bytes = new byte[1024];
// 4.读取数据并写出
while (inputStream.read(bytes) != -1){
outputStream.write(bytes);
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
内容追加
public void appendText() {
FileOutputStream out;
try {
out = new FileOutputStream("g:/test1.txt", true);
String str = "----追加数据----";
byte[] b = str.getBytes();
for(int i=0; i<b.length; i++) {
out.write(b[i]);
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2、字符流操作文件,进行文件的读取写入
public class CharacterStream {
public static void main(String[] args) {
// 1.实例化文件对象
File inFile=new File("g:/test.txt");
File outFile=new File("g:/test1.txt");
// 2.实例化输入输出流对象
FileReader fileReader;
FileWriter fileWriter;
try {
fileReader = new FileReader(inFile);
fileWriter=new FileWriter(outFile);
int len = 0;
//循环来判断是否读取到文件的末尾
while ((len=fileReader.read())!=-1){
fileWriter.write(len);
}
fileReader.close();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、字节缓冲流操作文件,进行文件的读取写入
字节缓冲流内置了一个缓冲区(Buffered),第 一次调用read方法时尽可能多地从数据源读取数据到缓冲区,后续再到用read方法时先看看缓冲区中是否有数据。如果有则读缓冲区中的数据,如果没有再将数据源中的数据读入到缓冲区。这样可以减少直接读数据源的次数。
通过输出流调用write方法写入数据时,也先将数据写入到缓冲区,缓冲区满了 之后再写入数据目的地,这样可以减少直接对数据目的地写入次数。
使用了字节缓冲流可以减少I/O操作次数,提高效率。
public class ByteBufferedStream {
public static void main(String[] args) {
FileInputStream inputStream;
FileOutputStream outputStream;
//创建文件输入流,底层流,通过它构造缓冲输入流
try {
inputStream = new FileInputStream("g:/test.txt");
BufferedInputStream bis = new BufferedInputStream(inputStream);
outputStream = new FileOutputStream("g:/test1.txt");
BufferedOutputStream bos = new BufferedOutputStream(outputStream);
//开始时间
long startTime = System.nanoTime();
//准备一个缓冲区,这个缓冲区与缓冲区内置的缓冲区不同,决定是否进行I/O操作的次数的是缓冲区内置的缓冲区,不是次缓冲区
byte[] buffered = new byte[1024];
//首先读取一次
int len = bis.read(buffered);
while (len != -1) {
bos.write(buffered, 0, len);
len = bis.read(buffered);
}
bis.close();
bos.close();
inputStream.close();
outputStream.close();
//结束时间
long elapsedTime = System.nanoTime()- startTime;
System.out.println("耗时"+(elapsedTime/1000000.0)+"毫秒");
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、字符缓冲流操作文件,进行文件的读取写入
代码类似,就不往上贴了
5、对象流操作文件,进行文件的读取写入
对象流:以“对象”为数据源,但是必须将传输的对象进行序列化与反序列化操作。序列化以后的对象可以保存到磁盘上,也可以在网络上传输, 使得不同的计算机可以共享对象
ObjectInputStream 称为 反序列化流,利用输入流从文件中读取对象
ObjectOutputStream 称为 序列化流,利用输出流向文件中写入对象
特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。
商品对象
public class Goods implements Serializable {
private String name;
private Double price;
private int number;
public Goods(String name, Double price, int number) {
this.name = name;
this.price = price;
this.number = number;
}
public Goods() {
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
", price=" + price +
", number=" + number +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
对象流操作文件
public class ObjectStream {
public static void main(String[] args){
writeText();
readText();
}
public static void writeText() {
File file;
FileOutputStream fos;
ObjectOutputStream oos;
try {
file = new File("g:/test.txt");
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(new Goods("鞋",20.0 ,10));
oos.writeObject(new Goods("电脑" ,5000.0 ,10));
oos.writeObject(null);
//清空缓冲区
oos.flush();
//关闭资源
fos.close();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void readText() {
File file;
FileInputStream fis;
ObjectInputStream ois;
Object obj;
try {
file = new File("g:/test.txt");
fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
//循环输出
while ((obj=ois.readObject()) != null) {
System.out.println(obj);
}
fis.close();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
输出结果:
附:参考资料
1、java IO流详解
2、java IO流详解
3、对象流ObjectInputStream/ObjectOutputStream详解