天天看点

IO流(字节流、字符流、缓冲流)流的分类

流的分类

按操作数据单位不同分为:字节流(8bit)二进制文件,字符流(按字符)

按数据流的流向不同分为:输入流、输出流

按流的角色不同分为:节点流,处理流/包装流

抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

字节输入流(InputStream )

相关子类

FileInputStream:文件输入流

BufferedInputStream:缓冲字节输入流

ObjectInputStream:对象字节输入流

FileInputStream文件输入流

以字节形式处理流,主要是处理二进制文件。

@Test
public void reader01() throws IOException {
    String url = "C:\\Users\\lenovo\\Desktop\\hello.txt"; //文件地址
    int readData = 0;
    FileInputStream fileInputStream = null;
    try {
        fileInputStream = new FileInputStream(url); //创建流
        while ((readData = fileInputStream.read()) != -1) { // 数为-1时则表示读取完
            System.out.print((char) readData);
        }
    } catch (IOException e) {
        log.error(e.getMessage());
    }  finally {
        fileInputStream.close(); // 关闭流
    }
}
           

上述代码是进行单字节进行读取所以速度相对较慢,也可以指定一次读取的字节数量。

fileInputStream = new FileInputStream(url); //创建流
byte[] bytes = new byte[15]; //一次读取的字节数量
// 数为-1时则表示读取完
// 如果读取正常readData值为读取字符数量
while ((readData = fileInputStream.read(bytes)) != -1) {
	System.out.print(new String(bytes, 0, readData));
}
           

字节输出流(OutputStream)

相关子类:FileOutputStream字节输入流

@Test
public void write01() throws IOException {
    FileOutputStream fileOutputStream = null;
    String url = "C:\\Users\\lenovo\\Desktop\\a.txt"; //文件地址
    String text = "123456789"; //需要写入的数据
    try {
        // new FileOutputStream(url)这种方式写入文件是覆盖的方式
        // new FileOutputStream(url, true);这种方式写入文件是追加的方式
        fileOutputStream = new FileOutputStream(url, true);
        // write(byte b[], int off, int len)
        // write(byte b[])
        fileOutputStream.write(text.getBytes(), 1, 4); //将文件写入
    } catch (FileNotFoundException e) {
        log.error(e.getMessage());
    } finally {
        fileOutputStream.close(); //关闭连接
    }
}
           

字符输入流(FileWriter)

FileWriter常用方法

1、 new FileWriter(File/String):覆盖模式,相当于流的指针在首端

2、new FileWriter(File/String,trule):追加模式,相当于流的指针在尾端’

3、 write(int):写入单个字符

4、write(char[]):写入指定数组

5、write(char[],off,len):写入指定数组的指定部分

6、write (string) :写入整个字符串

7、write(string,off, len):写入字符串的指定部分

注意!!!FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!

@Test
public void write() throws IOException {
    FileWriter fileWriter = null;
    String url = "C:\\Users\\lenovo\\Desktop\\note.txt"; //文件地址
    try {
        String text = "风雨过后,能见彩虹。";//写入文件内容
        fileWriter = new FileWriter(url);//开启流
        //表示写入位置0-5的字符
        fileWriter.write(text,0,5);
        System.out.println("程序结束");
    } catch (FileNotFoundException e) {
        log.error(e.getMessage());
    } finally {
        //关闭流
        if (fileWriter != null) {
            fileWriter.close();
        }
    }
}
           

字符输入流(FileReader)

@Test
public void read01() throws Exception {
    FileReader fileReader = null;
    String Url = "C:\\Users\\lenovo\\Desktop\\hello.txt";//文件地址
    int readData = 0;
    try {
        fileReader = new FileReader(Url); //启动流
        char[] chars = new char[24]; //流每次读取文件大小
        //fileReader.read(chars)等于-1表示文件读取完成
        //readData的值为读取的文件大小
        //fileReader.read如果写入读取大小则每次读取一个字符
        while ((readData = fileReader.read(chars)) != -1) {
            System.out.print(new String(chars, 0, readData));
        }
    } catch (FileNotFoundException e) {
        log.error(e.Message);
    } finally {
        //关闭流
        if (fileReader!= null) {
            fileReader.close();
        }
    }
}
           

缓冲流

缓冲流的作用就是对字节、字符流更高效的读写。字符缓冲流(BufferedWriter、BufferedReader)和字节缓冲流(BufferedInputStream、BufferedOutputStream)

缓冲流中使用了修饰模式。修饰模式大致思想如下。

创建抽象类Reader_

public abstract class Reader_ {
    public void fileReader(){}

    public void stringReader(){}
}
           

分别创建FileReader_、StringReader_继承Reader_并实现方法

public class StringReader_ extends Reader_{
    public void stringReader() {
        System.out.println("stringReader");
    }
}
           
public class FileReader_ extends Reader_{
    public void fileReader() {
        System.out.println("fileReader");
    }
}
           

在BufferedReader_中定义属性Reader_,通过构造器传入的reader属性对FileReader、StringReader_中的方法调用

public class BufferedReader_ {
    private Reader_ reader;

    public BufferedReader_(Reader_ reader) {
        this.reader = reader;
    }

    public void fileReader() {
        reader.fileReader();
    }

    public void stringReader() {
        reader.stringReader();
    }
}
           

测试

public class demo {
    public static void main(String[] args) {
        BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
        BufferedReader_ bufferedReader_1 = new BufferedReader_(new StringReader_());

        bufferedReader_.fileReader();
        bufferedReader_1.stringReader();
    }
}
           

字符缓冲流

注意:

1、BufferedWriter和BufferedReader是按照字符操作的

2、不要去操作二进制文件(视频、录音等),不然可能造成文件损坏

字符缓冲输出流BufferedWriter

//文件输出流
@Test
public void write() throws IOException {
    // 文件地址
    String url = "C:\\Users\\lenovo\\Desktop\\note.txt"; 
    // 将FileWriter转换成BufferedWriter
    // new FileWriter(url, true)中的true表示以追加形式写入,没有true则为清空写入
    BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(url, true));
    String text = "风雨过后";
    //写入
    bufferedWriter.write(text);
    // 关闭流
    System.out.println("写入成功");
    bufferedWriter.close();
}
           

字符缓冲输入流BufferedReader

//文件输入流
public static void main(String[] args) throws Exception {
        String url = "C:\\Users\\lenovo\\Desktop\\note.txt";
        // 创建BufferedReader
        BufferedReader br = new BufferedReader(new FileReader(url));
        String s; //按行读取
    	// s为null则表示读取完
        while ((s = br.readLine()) != null) {
            System.out.println(s);
        }
        // 关闭流
        br.close();
    }
           

字节缓冲流

想要操作二进制文件则使用BufferedInputStream和BufferedOutputStream来操作。他们既可以操作二进制文件也可以操作文本文件。因为二进制是根本。

public class BufferedCopy02 {
    public static void main(String[] args) throws IOException {
        String url = "C:\\Users\\lenovo\\Desktop\\1527.wav";
        String newUrl = "C:\\Users\\lenovo\\Desktop\\海贼王.wav";
        //字节缓冲输入流
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(url));
        //字节缓冲输出流
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(newUrl));
        //每次读取字节大小
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bufferedInputStream.read(buffer))!= -1) { //读取并写入 -1读取完成
            bufferedOutputStream.write(buffer, 0, len);
        }
        // 关闭流
        bufferedOutputStream.flush();
        bufferedInputStream.close();
    }
}
           

节点流/处理流

通过序列化和反序列化的方式将数据和数据类型保存到文件中。ObjectOutputStream输出流和ObjectInputStream输入流

注意事项和细节说明

1)读写顺序要一致

2)要求实现序列化或反序列化对象,需要实现 Serializable

3)序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性

4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员

5)序列化对象时,要求里面属性的类型也需要实现序列化接口

6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

ObjectOutputStream输出流

public class ObjectOutputStream_ {
    public static void main(String[] args) throws IOException {
        String url = "C:\\Users\\lenovo\\Desktop\\data.dat"; //文件地址
        ObjectOutputStream oos = null;
        try {
            // 创建流
            oos = new ObjectOutputStream(new FileOutputStream(url));
            //根据对应的类型写入数据
            oos.writeChar(1);
            oos.writeDouble(1.1);
            oos.writeUTF("username");
            oos.writeObject(new Dog());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            // 关闭流
            oos.close();
        }
    }
}
// Serializable序列化
class Dog implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
}
           

ObjectInputStream输入流

@Slf4j
public class ObjectInputStream_ {
    public static void main(String[] args) throws IOException {
        String url = "C:\\Users\\lenovo\\Desktop\\data.dat"; //文件地址
        ObjectInputStream ois = null;
        try {
            // 开启输入流
            ois = new ObjectInputStream(new FileInputStream(url));
            // 数据类型要与写入数据类型一致
            System.out.println(ois.readChar());
            System.out.println(ois.readDouble());
            System.out.println(ois.readUTF());
            System.out.println(ois.readObject());
        } catch (IOException | ClassNotFoundException e) {
            log.error("Error reading fileReader_", e.getMessage());
        }  finally {
            ois.close();
        }
    }
}