今天我们来说一下在Java里对文件的操作,IO流(输入输出流)。首先在计算机中文件在计算机上的信息集合,可以是文本、图片、视频等 。文件是以二进制的方式存放的
输入流:可以从其中读入一个字节序列的对象称作输入流
输出流:可以从其中写入一个字节序列的对象称作输出流
字符序列的来源地和目的地可以是文件(通常是)、网络连接、内存块等
在常用类中抽象类InputStream和OutPutStream构成了输入和输出类层次结构的基础。它们也被称为字节输入/输出流。它们是所有类字节输入/输出流的父类。
因为字节流是以一个字节来作为处理的基本单位,对于使用Unicode形式储存的信息(文本信息)不是特别方便的去进行处理,因为在Unicode中每个字符都使用了多个字节来表示。抽象类Reader和Writer中存在一个继承出来一个专门用于处理Unicode字符的单独类层次结构,它们是基于两个字节的Char值(即一个Unicode码元)进行读写操作的,而不是一个字节
对非文本文件建议使用字节流
package com.cheng.IOLearn; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class FileCopy { public static void main(String[] args) { // 1、创建文件的输入流,将文件读入到程序 // 2、创建文件到输出流,将读取到的文件数据,写入到指定到文件 FileInputStream fileInputStream = null; FileOutputStream fileOutputStream = null; String filePath = "//Users//chenzouquan//Desktop//未命名文件夹//截屏2021-10-20 下午5.21.49.png"; String destPath = "//Users//chenzouquan//Desktop//未命名文件夹//text.png"; try { fileInputStream = new FileInputStream(filePath); fileOutputStream = new FileOutputStream(destPath); // 定义一个字节数组,提高读取效率 byte[] buf = new byte[1024]; int readLen = 0; while ((readLen = fileInputStream.read(buf)) != -1){ // 读取到后,就写入到文件,即边读边写 fileOutputStream.write(buf,0,readLen);// 一定要使用这个方法 } System.out.println("拷贝成功"); } catch (IOException e) { e.printStackTrace(); }finally { // 关流 try { if (fileInputStream != null){ fileInputStream.close(); } if (fileOutputStream != null){ fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
对文本文件建议使用字节流
package com.cheng.IOLearn; import java.io.FileReader; import java.io.IOException; public class LearnFileReader { public static void main(String[] args) { // 1.指定文本路径 String strPath = "//Users//chenzouquan//Desktop//未命名文件夹//test.txt"; // 2、创建文件的输入流,将文件读入到程序 FileReader fileReader = null; int data = 0; try { fileReader = new FileReader(strPath); // 读取到后,就写入到文件,即边读边输出 while( (data = fileReader.read()) != -1){ System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } finally { // 关流 try { fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
在进行操作的要点:在执行完输入和输出操作后一定要记得关流(close)或者刷新流(flush),负责文件不能保存原因是在程序执行close或者flush之前并没有真正的的修改文件而是在执行close或者flush方法中进行正式的修改文件。close方法中会执行flush方法所以我们一般只要进行关流就足够了。
节点流:可以从一个数据源进行读写操作(如FileReader/FileWriter,FileInputStream/FileOutputStream…)
处理流:包装一个节点流或者处理流,对它们进行业务拓展给程序提供更好的读写功能(如BufferedReader/BufferedWriter…)
从源码上看这里使用了装饰器模式:即把一个装饰器对象中存入一个要进行操作的对象,在这个装饰器对象里对这个对象进行操作
以BufferedReader为例,他有属性Reader所以可以封装Reader子类进行操作
package com.cheng.IOLearn; public abstract class Reader_ { public void Reader_File() { } } class FileReader_ extends Reader_{ @Override public void Reader_File(){ System.out.println("FileReader_"); } } class StringReader_ extends Reader_{ @Override public void Reader_File(){ System.out.println("StringReader_"); } } /** * 处理流/包装流 */ class BufferedReader_ extends Reader_{ private Reader_ reader; public BufferedReader_(Reader_ reader) { this.reader = reader; } // 下面可以扩展对应功能 }
储存几个数据包括数据类型
Int num; char a; String str;
public class TestObjectOutputStreamLearn { public static void main(String[] args) throws IOException { // 序列化保存文件位置 String path = "//Users//chenzouquan//Desktop//未命名文件夹//data.dat"; ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path)); // 序列化数据 oos.write(100); oos.writeChar('a'); oos.writeUTF("测试"); // 序列化对象要让需要序列化的对象实现 Serializable接口 oos.writeObject(new Cat()); // 关流 oos.close(); System.out.println("序列化完毕"); } }
Java对象
public class Cat implements Serializable { // 提供序列化版本号,这样在类修改后,序列化和反序列化的时候就会认为这是一次更新而不是一个新的类 private static final long serialVersionUID = 1L; private String name = "hello"; int age = 11; public String CarName(){ return this.name; } public Cat(String name, int age) { this.name = name; this.age = age; } public Cat() { } }
public class TestObjectOutputStreamLearn { public static void main(String[] args) throws IOException, ClassNotFoundException { // 文件位置 String path = "//Users//chenzouquan//Desktop//未命名文件夹//data.dat"; ObjectInputStream oos = new ObjectInputStream(new FileInputStream(path)); // 读取数据要和序列化顺序一致 int i = oos.readInt(); char c = oos.readChar(); String s = oos.readUTF(); System.out.println(i+c+s); Object o = oos.readObject(); // 如果使用原来的对象的方法和属性,要转化为原来对象 Cat cat = (Cat) o; cat.CarName(); oos.close(); } }