java IO

概述

Stream

1.什么是流?

流是一个抽象概念,是对数据源的抽象,数据源可以是文件/网络/内存等。Java程序中数据的输入/输出都是以流的方式进行,同时,流具有方向性,以当前应用程序作为参考,数据从程序流向数据源称之为输出流;数据从数据源流向当前应用程序称之为输入流

2.流的种类?
  • 字节流/字符流: 按照应用从流中读出/写入的数据类型是byte / char划分
  • 输入流/输出流: 按照流的流向划分
3.数据源
  • File : FileXXXX
  • Memory : ByteArrayXXXStream等
  • Network: SocketInputStream等
4.包装上述流,增加额外功能
  • 线程间输入输出数据:Thread a(writer) -> Thread b(Reader) --> PipedXXX
  • 缓存流:读取/写入数据提供缓冲,BufferedXXXX
  • 多个输入流:保存一组输入流,挨个读取每个输入流中的数据 SequenceInputStream
  • 读取/写入java原始类型/对象类型: ObjectXXXX, DataXXXX

示例代码

下文中示例代码中依赖的常量

public final class TestConstants {
    public static final String READ_FILE_NAME = "src/main/resources/test-case-stream-read.txt";
    public static final String WRITE_FILE_NAME = "src/main/resources/test-case-stream-write.txt";
}
文件

字节流操作示例:直接从磁盘中的文件读取/写入数据

/**
 *  字节流: 数据源是文件
 */
@Test
public void testFile() {
    byte[] dataSource = "Data Source: File".getBytes();
    try (FileOutputStream out = new FileOutputStream(TestConstants.WRITE_FILE_NAME)) {
        out.write(dataSource);
    } catch (IOException e) {
        e.printStackTrace();
    }

    byte[] readData = new byte[dataSource.length];
    try (FileInputStream in = new FileInputStream(TestConstants.WRITE_FILE_NAME)) {
        in.read(readData);
    } catch (IOException e) {
        e.printStackTrace();
    }
    Assert.assertArrayEquals(dataSource, readData);
}

字符流操作示例:内部使用InputStreamReader/OutputStreamWriter桥接,完成底层File中字节到字符的转换,转换实现类使用StreamDecoder/StreamEncoder

/**
 * 字符流: 文件作为数据源
 */
@Test
public void testFile() {
    String dataSource = "Data Source: File";
    try (FileWriter writer = new FileWriter(TestConstants.WRITE_FILE_NAME)) {
        writer.write(dataSource);
    } catch (IOException e) {
        e.printStackTrace();
    }
    char[] readData = new char[dataSource.length()];
    try (FileReader reader = new FileReader(TestConstants.WRITE_FILE_NAME)) {
        reader.read(readData);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Assert.assertEquals(dataSource, new String(readData));
}
内存

字节流操作示例:直接读取/写入内存中的字节数组,close方法不影响流的使用。

/**
 * 字节流:数组源是内存中的字节数组
 */
@Test
public void testByteArray() {
    byte[] dataSource = "Data Source: Byte array".getBytes();
    //写入操作
    byte[] dataFromOut = null;      //作为读取的输入源
    try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
        out.write(dataSource);              // 写数据到内存中的字节数组
        dataFromOut = out.toByteArray();
    } catch (IOException e) {
        e.printStackTrace();
    }
    //读取操作
    byte[] result = new byte[dataFromOut.length];
    try (ByteArrayInputStream in = new ByteArrayInputStream(dataFromOut)) {
        in.read(result);
    } catch (IOException e) {
        e.printStackTrace();
    }
    Assert.assertArrayEquals(result, dataSource);
}

字符流操作示例: 直接读取/写入内存中的字符数组,close方法不影响流的使用。

/**
 * 字符流: 数据源是字符数组
 */
@Test
public void testCharArray() throws IOException {
    String dataSource = "Data Source: char array";
    //写入操作
    CharArrayWriter writer = new CharArrayWriter();
    writer.write(dataSource);
    String writerData = writer.toString();
    Assert.assertEquals(writerData, dataSource);
    //读取操作
    CharArrayReader reader = new CharArrayReader(writer.toCharArray());
    char[] readerData = new char[dataSource.length()];
    reader.read(readerData);
    Assert.assertEquals(dataSource, new String(readerData));
}
增加额外功能

字节流 -字符流 桥接:实现字符流与字节流之间的相互转换。继承自Reader接口,依赖InputStream接口,使用StreamDecoder完成转换工作,所有方法的请求都委托给StreamDecoder去完成。


/**
 * 字符流: 实现字符流和字节流直接的转换
 */
@Test
public void testBridge() {
    String dataSource = "byte Stream - char Stream";
    try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(TestConstants.WRITE_FILE_NAME))) {
        writer.write(dataSource);
    } catch (IOException e) {
        e.printStackTrace();
    }
    try (InputStreamReader reader = new InputStreamReader(new FileInputStream(TestConstants.WRITE_FILE_NAME))) {
        char[] readData = new char[dataSource.length()];
        reader.read(readData, 0, readData.length);
        Assert.assertArrayEquals(dataSource.toCharArray(), readData);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

缓冲功能:内容使用数组来存储待读取和待写入的数据,提供一个缓冲区。

/**
 * 字节流: 包装文件流,增加缓冲功能, 提高流的读取/写入效率
 */
@Test
public void testBuffered() {
    byte[] dataSource = "Data Source: other input stream -> file".getBytes();
    try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(TestConstants.WRITE_FILE_NAME))) {
        out.write(dataSource);
    } catch (IOException e) {
        e.printStackTrace();
    }
    byte[] readData = new byte[dataSource.length];
    try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(TestConstants.WRITE_FILE_NAME))) {
        in.read(readData);
    } catch (IOException e) {
        e.printStackTrace();
    }
    Assert.assertArrayEquals(dataSource, readData);
}

/**
 * 字符流: 增加缓存功能, 读取一行文本方法readLine()
 */
@Test
public void testBuffered() {
    String[] dataSource = {"test1", "test2", "test3", "", "测试1", "测试2"};
    try (BufferedWriter writer = new BufferedWriter(new FileWriter(TestConstants.WRITE_FILE_NAME))) {
        for(String str : dataSource) {
            writer.write(str);
            writer.newLine();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    try (BufferedReader reader = new BufferedReader(new FileReader(TestConstants.WRITE_FILE_NAME))) {
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

管道:缓冲区在读线程这边(PipedInputStream类中)

Pipe

/**
 *字节流: 在线程之间单向传递字节数据
 */
@Test
public void testBytePiped() throws IOException {
    byte[] dataSource = "Data Source: byte pipe test".getBytes();
    PipedOutputStream out = new PipedOutputStream();
    PipedInputStream in = new PipedInputStream(out);
    //发送数据线程
    new Thread(()->{
        try {
            out.write(dataSource);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();

    byte[] readData = new byte[dataSource.length];
    in.read(readData);

    Assert.assertArrayEquals(dataSource, readData);
}

/**
 * 字符流: 实现线程之间的单向管道
 */
@Test
public void testPiped() throws IOException {
    String dataSource = "Data Source :Piped test";
    PipedWriter writer = new PipedWriter();
    PipedReader reader = new PipedReader(writer);
    //发送数据线程,本线程接收数据
    new Thread(() -> {
        try {
            writer.write(dataSource);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();

    char[] readData = new char[100];
    int count = reader.read(readData);
    System.out.println(new String(readData, 0, count));
}

退回读出的数据:使用一个数组存储被退回的数据,每次读取优先读取该数组,后读取流中的数据

/**
 * 字节流: 读取一个字节,然后退回,重新读取
 * @throws FileNotFoundException
 */
@Test
public void testPushBack() throws FileNotFoundException {
    try (PushbackInputStream in = new PushbackInputStream(new FileInputStream(TestConstants.READ_FILE_NAME))) {
        int value1 = in.read();
        in.unread(value1);
        int value2 = in.read();
        Assert.assertEquals(value1, value2);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * 字符流: 读取一个字节后退回到流中,重新读取
 */
@Test
public void testPushBack(){
    try (PushbackReader reader = new PushbackReader(new FileReader(TestConstants.READ_FILE_NAME))) {
        char ch1 = (char)reader.read();
        reader.unread(ch1);
        char ch2 = (char) reader.read();
        Assert.assertEquals(ch1, ch2);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

多个输入流,循环读取:

/**
 * 读取多个流中的数据
 * @throws IOException
 */
@Test
public void testSequenceInputStream() throws IOException {
    byte[] dataSource1 = "Input Stream 1".getBytes();
    byte[] dataSource2 = "Input Stream 2".getBytes();
    ByteArrayInputStream in1 = new ByteArrayInputStream(dataSource1);
    ByteArrayInputStream in2 = new ByteArrayInputStream(dataSource2);
    SequenceInputStream in = new SequenceInputStream(in1, in2);
    int length = Math.max(dataSource1.length, dataSource1.length);
    byte[] data = new byte[length];
    int count;
    while ((count = in.read(data)) != -1) {
        System.out.println(new String(data, 0, count));
    }
    in.close();
}

读取Java基本类型和String类型数据

/**
 * 字节流: 基本类型和String的写入和读取
 */
@Test
public void testReadPrimitive() {
    int dataSourceInt = 1;
    String dataSource = "Text Content";
    //写入数据
    try (DataOutputStream out = new DataOutputStream(new FileOutputStream(TestConstants.WRITE_FILE_NAME))) {
        out.writeInt(dataSourceInt);
        out.writeUTF(dataSource);
    } catch (IOException e) {
        e.printStackTrace();
    }
    //读取数据
    try (DataInputStream in = new DataInputStream(new FileInputStream(TestConstants.WRITE_FILE_NAME))) {
        int value1 = in.readInt();
        String value2 = in.readUTF();
        Assert.assertEquals(dataSourceInt, value1);
        Assert.assertEquals(dataSource, value2);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

读取/写入对象类型到字节:

/**
 * 测试数据类型,需要实现序列化
 */
public class TestData implements Serializable {
    private static final long serialVersionUID = 7926567675530245735L;
    private String name;
    private int age;

    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;
    }
}
/**
 * 字节流: 读取/写入对象
 */
@Test
public void testObjectStream() {
    TestData testData = new TestData();
    testData.setName("object Stream");
    testData.setAge(24);
    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(TestConstants.WRITE_FILE_NAME))) {
        out.writeObject(testData);
    } catch (IOException e) {
        e.printStackTrace();
    }
    TestData object = null;
    try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(TestConstants.WRITE_FILE_NAME))) {
        object = (TestData) in.readObject();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    Assert.assertEquals(testData.getName(), object.getName());
    Assert.assertEquals(testData.getAge(), object.getAge());
}

java.io package

注意:数据源是一个File,Memory数据结构,在下文中称为原始流,数据源是其他底层数据流下文称为包装流

input stream (字节流)

Input Stream

描述:数据流入应用程序(data source -> application),读取的数据是字节

相关类

  1. FileInputStream : 数据源是文件
  2. ByteArrayInputStream:数据源是内存中的字节数组
  3. SequenceInputStream:定义一组输入流,读取完一个流后,自动切换到下一个,直到最后一个流被读取完。每次read操作只会读取一个流中的内容。
  4. PipedInputStream:定义一个管道,实现线程之间的数据传递,接收数据端
  5. ObjectInputStream:读取使用ObejctOutputStream写入的对象
  6. FilterInputStream:包装InputStream,增加额外功能的类继承自该类,包装器模式
  7. BufferedInputStream:增强输入流功能,带有一个缓存区
  8. DataInputStream:读取DataOutputStream写入的基本类型值和String
  9. PushbackInputStream:支持读取的数据推回流中,稍后在读取
  10. StringBufferInputStream and LineNumberStream:已废弃

output stream(字节流)

Output Stream

描述:数据流出应用程序(application ->data source),写的数据是字节

类介绍

  1. FileOutputStream:往文件中写入数据,支持追加写入
  2. ByteArrayInputStream:往字节数据中写入数据,可使用toByteArray(),toString()取回数据,也可以写入其他输出流WriterTo(out)
  3. PipedOutputStream :定一个管道,实现线程之间的数据传递,发送数据
  4. FilterOutputStream :包装其他输出流
  5. ObjectOutputStream : 直接写入对象类型,可使用ObjectInputStream读取
  6. BufferedOutputStream :带缓冲区的写入
  7. DataOutputStream :写入java基本类型数据

Reader(字符流)

Reader

描述:数据流入应用程序(data source -> application),读取的数据是字符,字节到字符的转换使用StreamDecoder类,该类也继承自Reader

类介绍

  1. FileReader:输入源是磁盘文件,继承自InputStreamReader,依赖FileInputStream
  2. BufferedReader:带缓冲区,读取原始流
  3. CharArrayReader : 输入源是内存中的字符数组
  4. StringReader : 输入源是内存中的字符串
  5. InputStreamReader: 字节流和字符流的桥,使用StreamDecoder完成字节流到字符流的转换
  6. PipedReader:管道,线程之间的通信,数据接收端
  7. FilterReader: 包装底层数据流
  8. PushbackReader:支持推回功能
  9. LineNumberReader:增加当前行号功能

Writer(字符流)

Writer

描述:数据流出应用程序(application -> data source),写入的数据是字符(串),字符到字节的转换使用StreamEncoder类,该类也继承自Writer

类介绍

  1. FileWriter:输出源是磁盘文件,继承自OutputStreamWriter,依赖FileOutputStream
  2. BufferedWriter:带缓冲区,写入原始流
  3. CharArrayWriter : 输出源是内存中的字符数组
  4. StringWriter : 输出源是内存中的字符串
  5. OutputStreamWriter: 字符流和字节流的桥接,使用StreamEncoder完成字符流到字节流的转换
  6. PipedWriter:管道,线程之间的通信,数据发送端
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值