File/IO
1、IO流原理及分类
1.1IO流的原理
在Java中将IO(输入输出)都是以"流(stream)"的形式进行的,用于处理数据的传输 如:读/写 文件,网络通讯。
Input:针对与当前程序来说的,从外部数据(文件,磁盘,数据库,网络,其他程序的内存中)输入到当前程序的 内存中称为Input
Output:从当前程序的内存中输出到其他位置(文件,其他程序的内存中,数据库,网络等)
1.2流的分类
-
按照操作数据单位的不同分类:字节流(一个字节读取),字符流(根据编码方式的不同对应着不同的字节数)
字节流:不会损坏文件,特别是对应的二进制文件,使用字节流不会顺坏文件
字符流:针对二进制文件,使用字符流可能会损坏文件,可以读取文本文件
-
按照数据的流向:输入流,输出流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
注:其他流的类是这四个类的子类;这四个都是抽象类,在使用时无法直接创建,需要创建他们的子类
- 按照流的角色分为:节点流,处理流/包装流
1.2.1 InputStream
InputStream抽象类是所有的字节输入流的基类
InputStream的常用子类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iALnfXdC-1649242572166)(C:\Users\admin\Desktop\文件与IO\tupian\inputstream.png)]
-
FileInputStream
public void readFile1() throws IOException { String filePath="D:\\1.txt"; System.out.println(); File file=new File(filePath); FileInputStream in=new FileInputStream(file); int readData=0; byte[] bytes=new byte[(int) file.length()]; //read():读取的下一个字节,如果读取到文件末尾则为-1; //in:是文件指针,读取了一个字节数据的后会将向后移动一位 while((readData=in.read())!=-1) { System.out.print((char)readData); } } @Test public void readFile2() throws IOException { String filePath="D:\\1.txt"; System.out.println(); File file=new File(filePath); FileInputStream in=new FileInputStream(file); byte[] bytes=new byte[(int) file.length()]; //read(byte[] byte):将读取到的数据保存到byte数组中去 in.read(bytes); String s=new String(bytes); System.out.println(s); }
-
BufferedInputStream
-
ObjectInputStream
OutputStream的常用子类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-80FWog3b-1649242572168)(C:\Users\admin\Desktop\文件与IO\tupian\outputstream.png)]
-
FileOutputStream
File file=new File("D:\\a.txt"); String s="hello world"; FileOutputStream out=new FileOutputStream(file); //write(byte[] byte):将byte数组的内容输写入到文件中 out.write(s.getBytes()); out.close();
File file=new File("D:\\a.txt"); String s="\nhello world\n"; //new FileOutputStream(file,true):追加到文件后面,不是覆盖 FileOutputStream out=new FileOutputStream(file,true); out.write(s.getBytes());
//创建文件的输入流 File inFile=new File("D:\\BaiduNetdiskDownload\\flink-1.13.1-bin-scala_2.12.tgz"); if(!inFile.exists())return; FileInputStream inputStream=new FileInputStream(inFile); //使用BufferedInputStream:对于InputStream进行封装 BufferedInputStream in=new BufferedInputStream(inputStream); //创建输出流 File outFile=new File("F:\\"+inFile.getName()); FileOutputStream out=new FileOutputStream(outFile,true); //使用BufferedOutputStream:对于OutputStream进行封装 BufferedOutputStream outputStream=new BufferedOutputStream(out); //将文件放入到数组中 long start=System.currentTimeMillis(); System.out.println(start); byte[] bytes=new byte[1024]; int readLength=0; //便读取边写入 while(((readLength=in.read(bytes))!=-1)) { outputStream.write(bytes,0,readLength); } System.out.println(System.currentTimeMillis()-start); if(outputStream!=null) outputStream.close(); if(in!=null) in.close();
Reader
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rwDS7Weg-1649242572169)(C:\Users\admin\Desktop\文件与IO\tupian\reader.png)]
-
FileReader
File file =new File("D:\\1.txt"); FileReader reader=new FileReader(file); int data=0; while((data=reader.read())!=-1) { System.out.print((char)+data); } reader.close();
Writer
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rHBr7XS7-1649242572170)(C:\Users\admin\Desktop\文件与IO\tupian\writer.png)]
-
FileWriter
File file =new File("D:\\1.txt"); FileWriter writer=new FileWriter(file); writer.write("nihao,你好".toCharArray()); writer.close();
节点流与包装流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efWoEpy7-1649242572171)(C:\Users\admin\Desktop\文件与IO\tupian\节点流与处理流.png)]
节点流:从一个特定的数据源读写数据,如:FilerInputStream,FileWriter等
处理流:是在已存在的流之上,为程序提供强大的读写功能,如:BufferedReader,BufferedInputStream
处理流针对于多个数据源的节点流进行了包装,丰富了IO的操作,提高了IO的灵活性。
两者的区别与联系:
节点流 | 处理流/包装流 |
---|---|
底层流,直接与数据源相接 | 包装了节点流,既可以消除不同节点流的差异性,也可以提供方便的方法来完成输入输出,处理流对 节点流进行了包装,使用了装饰器设计模式,不会与数据源直接相连 |
ObjectIn/OutputStream注意事项:
-
读取(反序列化)的顺序与序列化的顺序一致
-
实现序列化和反序列话的对象实现Serializable接口
-
序列化对象建议添加SerialVersionUID,为了提高版本的兼容性:
serialVersionUID
序列化ID,可以看成是序列化和反序列化过程中的“暗号”,在反序列化时,JVM会把字节流中的序列号ID和被序列化类中的序列号ID做比对,只有两者一致,才能重新反序列化,否则就会报异常来终止反序列化的过程。 -
序列化对象是,默认将所有的属性进行序列化,但是除了static与transient修饰的成员变量(类变量)
-
序列化对象是,属性的类型也要实现序列化接口
-
序列化对象具备可继承性,也就是如果某个类实现了序列化,则他的子类也默认实现了序列化
转换流
- InputStreamReader:Reader的子类,将InputStream(字节输入流)转换为Reader(字符输入流)
- OutputStreamWriter:Writer的子类,实现将OutputStream(字节流输出流)转换为Writer(字符输出流)
字节流 -> 字符流
InputStream in=new FileInputStream("D:\\1.txt");
//将FileInputStream的字节流转换为,InputStreamReader将字节流转换为字符流
//InputStreamReader为Reader的子类
InputStreamReader inputStream= new InputStreamReader(in);
//字符流的包装流
BufferedReader reader=new BufferedReader(inputStream);
未完待续。。。。。。。。