JDK源码:IO体系讲解

3ca899254ed1eabec62eab988752589d.jpeg

背景

IO流是Java中很重要的一部分内容,常用的数据传输,文件的上传和下载都和它分不开。

Java中的IO根据处理数据的方式,可以分为字节流和字符流,同时根据传输方向的不同,又可以分为输入流和输出流。

6aaf6acdcff3b8f023783781da5a4d57.png

图中,整理了在Java 8中根据上述分类的IO流,其中字节输入流有28种,字节输出流有18种,字符输入流有9种,字符输出流有8种,看到这么多的流,实际开发中经常使用到的只是其中的一部分。

比如:

  • 字节输入流中的FileInputStream、BufferedInputStream,

  • 字节输出流中的FileOutputStream、BufferedOutputStream

  • 字符输入流中的BufferedReader、InputStreamReader、FileReader

  • 字符输出流中的BufferedWriter、OutputStreamWriter、FileWriter等。

在图中已用黑色框图进行了突出标注。

实战案例

1、输入流

1.1 FileInputStream

源码
public class FileInputStream extends InputStream
{
    //【1】
    private final FileDescriptor fd;
    //【2】
    private final Object closeLock = new Object();
}

代码分析:

FileInputStream是Java IO中的一个类,用于从文件中读取数据。它继承自InputStream类,可以读取字节流。

  • FileInputStream可以打开一个文件,读取其中的数据,并将数据以字节流的形式返回。

  • 如果文件存在但是没有读取权限,FileInputStream会抛出SecurityException异常。

  • FileDescriptor 文件描述符

案例
/**
 * 字节流-输入流-FileInputStream
 *
 */
public class FileInputStreamTest {
    public static void main(String[] args) throws IOException {
        File file = new File("/Users/bryantmo/Desktop/code/springcloud_test/webdoor/src/test/java/com/bryant/io/1.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] bytes = new byte[1024];
        int read = 0;
        // 直接从磁盘读入到内存
        while ((read = fileInputStream.read(bytes)) != -1) {
            System.out.println(new String(bytes, 0, read));
            // 可能再输出到磁盘持久化
        }
    }
}

1f49d4548c1e989f5c7f25d740d8a338.png

1.2 ByteArrayInputStream

源码
public class ByteArrayInputStream extends InputStream {


    protected byte buf[];


    protected int pos;
}

代码分析:

ByteArrayInputStream 提供了一个从字节数组输入数据的流。主要功能如下:

  • buf:存储字节数据的数组,其中buf[pos]表示下一个要读取的字节。

  • pos:记录当前读取位置的索引,保证非负且不大于数组长度。

案例
/**
 * 输入流-字节流-ByteArrayInputStream
 */
@Slf4j
public class ByteArrayInputStreamTest {
    public static void main(String[] args) throws IOException {
        // 被读取的数据,内存
        byte[] bytes = "Hello world".getBytes();
        // ByteArrayInputStream 是 Java 中的一个类,它是 InputStream 的子类,用于从字节数组中读取数据。
        //这个类允许你将一个字节数组视为一个输入流,从而可以使用标准的 I/O 流操作来处理它。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes, 0, 3);
        while (byteArrayInputStream.read() != -1) {
            byteArrayInputStream.read(bytes);
            log.info("byteArrayInputStream#read: data = {}", new String(bytes));
        }


    }
}

3e5f763962f994a43430bcf7e60f7a47.png

1.3 BufferedInputStream

源码
public class BufferedInputStream extends FilterInputStream {
    private static int DEFAULT_BUFFER_SIZE = 8192;
    protected volatile byte[] buf;
    protected int count;
    protected int pos;
}

代码分析:

BufferedInputStream 是 FilterInputStream 的子类,用于对输入流进行缓冲处理。

缓冲输入流可以提高读取效率,因为它减少了与底层数据源的交互次数。

案例
/**
 * 输入流-字节流-缓冲输入流
 */
@Slf4j
public class BufferedInputStreamTest {


    public static void main(String[] args) throws IOException {
        File file = new File("/Users/bryantmo/Desktop/code/springcloud_test/webdoor/src/test/java/com/bryant/io/1.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 2);
        // 设置一个内存
        byte[] bytes = new byte[3];
        int byteRead;
        while ((byteRead = bufferedInputStream.read()) != -1) {
            // 直接从磁盘读入数据到内存,非常慢
            int read = bufferedInputStream.read(bytes);
            log.info("read: data = {}, read = {}", new String(bytes), read);
        }
    }
}

b3ee040e4684f08958a731373a22e035.png

1.4 BufferedReader

源码
public class BufferedReader extends Reader {


    private Reader in;


    private char cb[];


}

代码分析:

BufferedReader该类实现了一个带缓冲区的字符输入流。

  • in:表示底层的字符输入流。

  • cb[]:字符缓冲区,用于存储读取的数据,提高读取效率

案例
/**
 * 字符流-输入流-BufferedReader
 */
@Slf4j
public class BufferedReaderTest {
    public static void main(String[] args) throws IOException {
        File file = new File("/Users/bryantmo/Desktop/code/springcloud_test/webdoor/src/test/java/com/bryant/io/1.txt");
        FileReader fileReader = new FileReader(file);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            log.info("line : {}", line);
        }
    }
}

5bec6f952036952fc13673341f7681c9.png

2、输出流

2.1 FileOutputStream

源码
public class FileOutputStream extends OutputStream
{
    private final FileDescriptor fd;
}

代码分析:FileOutputStream类继承OutputStream

  • FileDescriptor fd,表示系统依赖的文件描述符,用于文件输出流操作。

案例
/**
 * 字节流-输入流-FileOutputStream
 *
 */
public class FileOutputStreamTest {
    public static void main(String[] args) throws IOException {
        String data = "字节流-输入流-FileInputStream";
        // 文件标识符
        File file = new File("/Users/bryantmo/Desktop/code/springcloud_test/webdoor/src/test/java/com/bryant/io/1.txt");
        FileOutputStream fileInputStream = new FileOutputStream(file);
        // 直接从内存写入磁盘
        fileInputStream.write(data.getBytes());
        fileInputStream.flush();
    }
}

abff9c4fbbb0ec48d479b8b45d22b5e0.png

2.2 ByteArrayOutPutStream

源码
public class ByteArrayOutputStream extends OutputStream {


    /**
     * The buffer where data is stored.
     */
    protected byte buf[];
    protected int count;
}

ByteArrayOutputStream的部分属性:

  • buf:一个受保护的字节数组,用于存储数据。

  • count:一个受保护的整型变量,记录已存储的数据量。

案例
/**
 * 字节流-输出流-ByteArrayOutputStream
 */
@Slf4j
public class ByteArrayOutputStreamTest {
    public static void main(String[] args) throws IOException {
        String newString = "Hello, World!";
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 底层是for循环,写入ByteArrayOutputStream的内存数组
        baos.write(newString.getBytes());
        // 读出内存数组:底层会新建一个数组,通过数组拷贝,并返回
        byte[] bytes = baos.toByteArray();
        log.info("bytes: {}", bytes);
        log.info("string: {}", new String(bytes));
    }
}

14123f83282c900a675881ef6959b353.png

2.3 BufferedOutputStream

源码
public class BufferedOutputStream extends FilterOutputStream {
    /**
     * The internal buffer where data is stored.
     */
    protected byte buf[];
    protected int count;
}

BufferedOutputStream的部分属性:

  • buf:一个受保护的字节数组,用于内部缓冲存储数据。

  • count:一个受保护的整型变量,记录缓冲区中已存储的数据量

案例
/** * 输出流-字节流-BufferedOutputStream
 * BufferedOutputStream通过内部维护一个缓冲区来减少对底层文件系统的调用次数,从而提高写入效率。
 */
@Slf4j
public class BufferedOutputStreamTest {
    public static void main(String[] args) throws IOException {
        // 设置一个内存数据
        String data = "Hello world...." + System.currentTimeMillis();
        // 输出流写入字符到磁盘
        File file = new File("/Users/bryantmo/Desktop/code/springcloud_test/webdoor/src/test/java/com/bryant/io/1.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file);


        // 这里我们测试了,缓冲区大小为2和222的预设值时,分别对应了底层不同的写入磁盘逻辑
//        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream, 2);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream, 222);
        bufferedOutputStream.write(data.getBytes());
        // flush()方法用于强制将缓冲区中的数据写入到底层的文件输出流中。即使缓冲区未满,调用flush()也会立即执行写入操作。
        bufferedOutputStream.flush();
    }
}

42eac46ca1e8c5f5c297203bd4726490.png

2.4 BufferedReader

源码
public class BufferedWriter extends Writer {


    private Writer out;


    private char cb[];
}

它是 Java 中的一个类,用于从字符输入流中读取文本,缓冲字符以提供高效的读取操作。BufferedReader 继承自 Reader 类,并且它提供了一个缓冲区,可以减少对底层数据源的访问次数,从而提高读取效率。

主要特点
  1. 缓冲:BufferedReader 使用内部缓冲区来存储从输入流中读取的字符,这样可以减少对底层数据源的访问次数。

  2. 高效读取:由于缓冲机制的存在,BufferedReader 提供了比直接使用 Reader 更高效的读取操作。

  3. 行读取:BufferedReader 提供了 readLine() 方法,可以方便地按行读取文本数据。

案例
/**
 * 字符流-输出流-BufferedWriter
 */
@Slf4j
public class BufferedWriterTest {
    public static void main(String[] args) throws IOException {
        String data = "hello world";
        File file = new File("/Users/bryantmo/Desktop/code/springcloud_test/webdoor/src/test/java/com/bryant/io/2.txt");
        FileWriter fileWriter = new FileWriter(file);
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        try {
            bufferedWriter.write(data);
            bufferedWriter.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

7aaa73dccea62374efde47722c87fe77.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后台技术汇

对你的帮助,是对我的最好鼓励。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值