I/O流:
- 用来完成java的输入输出工作,包括磁盘文件、设备、其他程序以及内存数据等等的输入输出
- I/O流支持多种数据类型,如:简单的二进制类型、原始类型、本地字符以及各种对象
- 基于流技术可以用来传递数据,还可以用来操作或格式化数据
- 所有的流都使用相同的模型来编写程序
- 一组I/O流指明了输入源和输出目的地
- 一种流是一组顺序的数据
I/O流的分类
从本质上:分为字符流(用来处理本地化乱码问题 一个中文占两个字节)和字节流
从功能上:分为对象流(只有字节流)、文件流(既有字节流又有字符流)、数据流、缓冲流等
下面将一些常用的流进行了总结。 - 字节流为输入输出提供了最原始的环境,字节流可以直接操作二进制数据, InputStream是定义Java的流式字节输入模式的抽象类,OutputStream是定义流式字节输出的抽象类,这两个类的方法都返回一个void值并在出错条件下引发IOException异常,
注意:in.read()方法返回的是int类型,1 int = 4 bi t= 8位,java将读出来的字节放在int型的最后一个字节,前面的24位空余 ,类似于拿一个可以放4个苹果的箱子放一个苹果进去,将这个苹果放在最后一个格子里面。
所有的流必须关闭,java垃圾回收机制不能做流的自动化回收。
下面的程序以文件字节流完成输入输出的过程,完成把文件a里面的内容读进来,并写出去到文件b里面。
FileInputStream in = new FileInputStream("./a.txt"); //绝对路径
FileOutputStream out = new FileOutputStream("./b.txt");
int info = -2; //因为-1是文件结束的标志,所以info初始化为-2
while(( info = in.read()) != -1) {
out.write(info);
out.flush(); //没有flush()数据将会在缓冲区里面,导致程序错误
}
- 带缓冲的字节流BufferedReader和BufferedWriter是java的缓冲流,但是在这里为了理解,我自己写了一个,声明一个缓冲数组,达到缓冲的目的。在前面的应用中我们使用的都是无缓冲 I/O,这意味着每次读写操作都依赖于低层的操作系统,这样效率很低,因为,每次请求常常要引发disk access, network activity,或者一些其他操作 。为了解决此问题,Java平台实现了缓冲I/O 流,缓冲输入流从内存中的一块缓冲区中读取数据,而当缓冲区为空时才调用本地的输入API, 类似的,缓冲输出流输出数据到缓冲区中,当输出缓冲区满时才调用本地的输出API
FileInputStream in = new FileInputStream("./1.zip"); //写出去
FileOutputStream out = new FileOutputStream("./2.zip");// 读进来
byte[] pool = new byte[1024]; //缓冲数组 数组长度可以自定义,但应该是8的倍数
int info =-2;
while ((info = in.read(pool, 0, 1024)) != -1) {
out.write(pool, 0, pool.length); // 不能1024 因为最后一次可能数组没有满
out.flush();
}
这是java本身的缓冲流,和我上面的代码功能一样。字符流常常遇到比单字符更大的字符单元,一般,使用一个行终止符来结束串字符。行结束符使用回车符和换行符
(“\r\n”),或者单个回车符 (“\r”),,或者单个换行符("\n")。Java支持在所有操作系统上创建的文本文件可能的行结束符。为了使用line-oriented的高效率 I/O我们必须使用BufferedReaderBufferedWriter
BufferedReader reader = new BufferedReader(new FileReader("./a.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("./d.txt"));
String info = null;
while ((info = reader.readLine())!= null) {
System.out.println(info);
writer.write(info + "\n"); //必须加上\n,不让读的文件没有换行
writer.flush(); // 必须有,不然数据在缓冲区
}
- 字符流尽管字节流提供了处理任何类型输入/输出操作的足够的功能,但它们不能直接操作字符,字符流面向字符,读写的单位是2字节,字符流以Reader和Writer为顶层。Reader是定义Java的流式字符输入模式的抽象类, Writer是定义流式字符输出的抽象类,这两个类的方法都返回一个void值并在出错条件下引发IOException异常
- Java平台使用的字符集在Java内部会自动转换成本地字符集,对应程序开发,使用字符流比字节流更简便,因为输入输出流会自动转换成本地的字符编码标准, 程序使用字符流代替字节流,自动匹配到本地字符编码,适应国际化 ,这样就不需要程序员做额外的工作 。
下面的程序以文件字符流完成输入输出的过程,完成把文件a里面的内容读进来,并写出去到文件b里面。
FileReader reader = new FileReader("./a.txt");
FileWriter writer = new FileWriter("./a.txt");
int info = -2;
while((info = reader.read()) != -1) {
writer.write(info);
writer.flush();
}
下面,是一个转换流的例子。
- 数据流(只有字节流没有字符流) 数据流在流动的时候有明确的数据类型这是我将稀疏数组存入文件的一篇博客,可以深刻体会数据流的应用
String[] name = {"xgz","wjr","ptt"};
int [] age = {1,1,1};
DataOutputStream out = new DataOutputStream(new FileOutputStream("./e.txt"));
for (int i = 0;i<3;i++) {
out.writeUTF(name[i]);
out.flush();
out.writeInt(age[i]);
out.flush();
//写出去的文件用记事本打开是乱码。因为编码格式原因,用GBK打开文本类型所以乱码 数据流在流动的时候有明确的数据类型
}
DataInputStream in = new DataInputStream(new FileInputStream("./e.txt"));
for (int i = 0;i < 3; i++) {
System.out.print(in.readUTF() +" ");
System.out.println(in.readInt() + 1); //可以读出int
}
- 对象流(只有字节流没有字符流)如果代开f文件依然是乱码,乱码原因和数据流原理一样,此种现象不要担心程序错误
Student类必须实现Serializable(标识接口 该接口没有方法)序列化接口,否则会报序列化异常错误,可以抽象理解为对象在传输的过程中被切块传输,到达目的地需要正确的序列才能正确的组装成原来的对象。
Student s1 = new Student("张三", 18);
Student s2 = new Student("李四", 19);
Student s3 = new Student("王五", 16);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./f.txt"));
out.writeObject(s1);
out.flush();
out.writeObject(s3);
out.flush();
out.writeObject(s2);
out.flush();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("./f.txt"));
for(int i = 0; i < 3; i++) {
Student s = (Student)in.readObject();
System.out.println(s);
}
- 标准流大多数操作系统标准流都有标准流,默认他们从键盘读取数据显示到显示器上,同时也支持用命令行来控制程序间的输入输出操作。 Java提供三种标准流,其中输入流:System.in,输出流:System.out、System.err,错误输出可以允许用户将错误信息保存到持久化介质中,这些流已经被自动定义不需要再打开. 标准流都是二进制流,System.out和system.err 是 PrintStream 对象。System.in是二进制流没有字符流对象为了把它变成字符流可以把System.in包装进InputStreamReader,下面程序从控制台不停地读直到"再见!"结束。
注意标准流不用关闭
.
BufferedReader sysReader = new BufferedReader(new InputStreamReader(System.in)/*转换流,标准流不用new*/);
PrintStream out = System.out;
PrintStream err = System.err;
String info = null;
while (true) {
info = sysReader.readLine();
out.println(info);
err.println(info);
if("再见!".equals(info)) {
break;
}
}