一、什么是IO流:
将数据从内存传输到外部存储设备的通道,管道。
IO流的分类:
1.按方向划分:<以JVM为参照物>
输入流:将<外部存储设备>中的数据读入到<内存>中。
输出流:将<内存>中的数据写入到<外部存储设备>中。
2.按单位划分:
字节流:以字节(8bit)为单位,能够传输所有类型的文件。
字符流:以字符为单位,一次可能读多个字节。.只能传输文本文件(能够被记事本打开.java/.txt/.html,并且不改变内容的文件)
只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
3.按功能划分:
节点流:具有基本的读写功能
过滤流:在节点流的基础上,增加了新的功能
二、IO流常用类库:
三、java IO流对象
1.字节输入(输出)流InputStream/OutputStream中输入字节流的继承图可见上图,可以看出:
InputStream/OutputStream 是所有的输入(输出)字节流的父类,它是一个抽象类。
常用子类FileOutputStream:文件字节输出流
常用方法为:(返回值类型都为void)
void write(int b):向外部存储设备中写入数据 void write(byte[] b) :向指定文件中写入 数组长度个 字节 void write(byte[] b, int off, int len) :向指定文件中写入数组中指定的字节 b:数组 off:开始下标 len:个数 void close(): 关闭资源
FileInputStream:文件字节输入流
常用方法: (返回值类型都为int)
int read():从输入流中读取一个字节,返回值表示字符的整数表现形式,若没有字符 则返回-1 int read(byte[] b):从输入流中读取多个字节,返回值表示读取的有效字节个数 int read(byte[] b, int off, int len) : b:数组 off:存储到数组的指定下标 len:存储个数
BufferedOutputStream/BufferedInputStream、DataOutputStream/DataInputStream、ObjectOuputStream/ObjectInputStream都是字节过滤流。
其中,BufferedOutputStream/BufferedInputStream 字节输入输出过滤缓冲流,可以提高IO的效率,减少磁盘的访问次数。数据存储在数据缓冲区中,需要使用flush方法 清空缓冲区。也可以直接使用close方法。
例如:
package test; import java.io.FileOutputStream; import java.io.IOException; /** * @author 超伟 * @date 2019年5月16日 * @博客: https://blog.csdn.net/MacWx */ public class testOutput { public static void main(String[] args) throws IOException { //创建文件输出流 FileOutputStream fo = new FileOutputStream("file/test.txt"); //往文件中写入一个char数据, fo.write(65); //创建一个byte类型数组 byte[] b = new byte[]{66,67,68,69}; //将此数组写入到文件中 //fo.write(b); //将此数组中的下标为1的开始,的后两个字符写入到文件中 fo.write(b, 0, 4); //关闭输出流 fo.close(); //FileOutputStream的两参构造方法,第一个参数传的是文件名, //第二个参数如果是true,则使文件添加,否则覆盖! FileOutputStream file = new FileOutputStream("file/test.txt",true); String s = "今天星期五"; byte[] cs = s.getBytes(); //将字符串数组添加写入文件中 file.write(cs); //关闭流 file.close(); } }
上面程序是将一个自定义的字符或者字符串通过FileOutputStream写入到文件中去的,那么怎么从一个文件中把数据读取到java虚拟机JVM并通过控制台打印出来呢?
package test; import java.io.FileInputStream; import java.io.IOException; /** * @author 超伟 * @date 2019年5月16日 * @博客: https://blog.csdn.net/MacWx */ public class testInput { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //创建文件读入流 FileInputStream f = new FileInputStream("file/test.txt"); //返回读入文件的整数表现形式 //int read = f.read(); byte b[] = new byte[3]; //测试通过数组读取文件中的信息 //f.read(b,0,2); //再通过死循环遍历读入的文件所有内容, //如果到最后一个字节为空即等于-1的时候break跳出循环 while(true){ int reads = f.read(); if (reads== -1) { break;//跳出死循环 } //输出读取到的字节,再强转回char类型 System.out.print((char)reads); } //关闭资源 f.close(); } }
DataOutputStream/DataInputStream 主要用来操作基本数据类型,和字符串的输入输出。
import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; public class TestDataOuputStream { public static void main(String[] args) throws IOException { //创建节点流 FileOutputStream fileOutputStream = new FileOutputStream("file/f.txt"); //创建过滤流 DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); //写操作,往文件中写入浮点数12.5; dataOutputStream.writeDouble(12.5); //关闭资源 dataOutputStream.close(); } }
ObjectOuputStream/ObjectInputStream 对象输入输出过滤流,主要增强缓冲区的功能,同时增强了操作基本数据类型和字符串类型的能力
可以操作对象
writeObject(Object obj):向外部存储设备写入对象数据类型
Object readObject():从外部存储设备读入对象,返回值为读入的对象
对象放在流上进行传输的过程称为对象序列化。
要求:自定义的类必须实现Serializable接口
需要注意:
i.被transient修饰的属性,不参与序列化
ii. java.io.EOFException 文件到达尾部
文件中只有一个对象,连续读取两次 就会报此异常
iii.如果参与序列化对象有对象类型的属性,则这个属性类型也必须实现Serializable
iv.当序列化对象为集合时,它的对象元素类型,也必须实现Serializable接口
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; public class TestObjectOutputStream { public static void main(String[] args) throws IOException { //创建节点流 FileOutputStream fileOutputStream = new FileOutputStream("file/d.txt"); //创建包装、过滤流 ObjectOutputStream oos = new ObjectOutputStream(fileOutputStream); //执行写操作 //写入一个对象 Student s = new Student("macw",22); oos.writeObject(s); //关闭资源 oos.close(); } } class Student implements Serializable{ //对学生对象 实现了序列化 private static final long serialVersionUID = 1L; private String name; private transient int age; //被transient修饰的属性,不参与序列化 private Address add = new Address(); 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 Student() { super(); } public Student(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } } class Address implements Serializable{}
谈一下使用IO流进行文件复制的操作:
用FileInputStream 和 FileOutputStream 实现文件的复制。
其基本实现流程为先使用FileInputStream.read()方法读取到文件中的数据,再将读取到JVM中的数据通过FileOutputStream.write()方法写入到想要复制的文件中。
还可以实现字节包装类(过滤流也加包装类,同一个意思)来增强缓冲区的功能,提高IO的效率,减少磁盘的访问次数。
例如:
使用IO流将图片“gril.jpg”复制到“file”文件下
package work; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * @author 超伟 * @date 2019年5月16日 * @博客: https://blog.csdn.net/MacWx */ public class t11 { public static void main(String[] args) throws IOException { //创建文件字节输入流对象, FileInputStream fileInputStream = new FileInputStream("E:\\java\\练习\\gril.jpg"); //创建文件字节输出流对象, FileOutputStream fileOutputStream = new FileOutputStream("file/gril.jpg"); //分别对输入输出流对象通过过滤流进行包装,提高IO的效率 BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); //记录程序运行开始复制时的当前时间,目的是为了测试本次复制效率如何 long start = System.currentTimeMillis(); //通过死循环遍历原文件中的每一个字节,遍历到最后字节为空即等于-1时跳出死循环 while (true) { int read = bufferedInputStream.read(); if (read == -1) { break; } //将读取到的每一个字节一次写入到复制的新文件中 bufferedOutputStream.write(read); } //关闭所有流资源 bufferedInputStream.close(); bufferedOutputStream.close(); long end = System.currentTimeMillis(); //通过程序结束时的当前时间减去开始时间查看复制效率 System.out.println(end - start); } }
这样就可以完成文件的简单复制操作了!
由于篇幅限制下一篇介绍IO流的字符输入输出流…