【Java IO系列】那字节流和字符流有什么区别?

🌱以贴近现实的【面试官面试】形式涵盖大部分Java程序员需要掌握的后端知识、面试问题,系列博客收录在我开源的JavaGetOffer中,会一直完善下去,希望收到大家的 ⭐️ Star ⭐️支持,这是我创作的最大动力: github.com/hdgaadd/Jav...

  • 📚本期博客内容为《Java IO系列》
  • 创作不易,不妨点赞、收藏、关注支持一下

1. IO的理解

面试官:你说下对Java IO的理解?

好的面试官,Java IO有两个参与对象,一个是IO源端 ,一个是想要和IO源端通信的各种接收端 如控制台、文件等,我们程序要保证的就是顺利的读取和顺利的写入。

2. 输入流

2.1 字节输入流读取方法

面试官:那要怎么读取字节流?

读取字节的抽象基类是InputStream,这个基类提供了3个方法可以来读取字节流。

  1. 从输入流读取下一个数据字节,值字节以0到255范围内的int返回。

    java 复制代码
    public abstract int read() throws IOException
  2. 从输入流读取一定数量的字节并将它们存储到缓冲区数组b中。

    java 复制代码
    public int read(byte b[]) throws IOException
  3. 从输入流读取最多len个字节的数据到字节数组中。

    java 复制代码
    public int read(byte b[], int off, int len) throws IOException

2.2 字节输入流读取实例

面试官:你说的这些不是实例,我要的是能真正读取的?

那可以用抽象基类的子类实现来读取,例如文件流FileInputStream

java 复制代码
new FileInputStream(SOURCE_PATH)

我们还可以在外面加一层缓存字节流来提高读取效率。

java 复制代码
new BufferedInputStream(new FileInputStream(SOURCE_PATH))

如果要把缓存流换成字符流来承接 ,方便使用readLine()读取某一行的话,可以使用转换流把字节输入流转换成字符输入流。

java 复制代码
new BufferedReader(new InputStreamReader(new FileInputStream(SOURCE_PATH)))

2.2 缓存流提高读取效率

面试官:为什么加一层缓存流就能提高读取效率?

是这样的。因为直接使用 FileInputStream 读取文件的话,每次调用 read() 都是从磁盘读取一个字节 ,而每次读取都是一次系统调用。系统调用是操作系统层面的调用,涉及到用户空间和内核空间之间的上下文切换,这些切换是很昂贵的。

而如果使用缓存流,一次性从文件里读取多个字节到缓存中,可以减少系统调用同时也减少了磁盘读取,提高了读取的效率。

2.3 字节输入流末尾

面试官:读取之后呢,我怎么知道文件读取到末尾了?

例如我刚刚说到的字节流基类InputStream的3个方法,当他们返回-1,就表明输入流到达了末尾。

2.4 字符输入流

面试官:字符流读取呢?

字符流的抽象基类是Reader,同样是提供了3个方法来支持字符流读取。

  1. 读取单个字符。

    java 复制代码
    public int read() throws IOException
  2. 将字符读入数组。

    java 复制代码
    public int read(char cbuf[]) throws IOException
  3. 将字符读入数组的一部分。

    java 复制代码
    abstract public int read(char cbuf[], int off, int len) throws IOException

然后字符流读取的实例是FileReader,同样可以使用缓存字符流提高读取效率。

java 复制代码
new BufferedReader(new FileReader(new File(SOURCE_PATH)))

3. 输出流

面试官:输出流你也讲一讲?

好的面试官。

字节输出流的抽象基类是OutputStream ,字符输出流的抽象基类是Writer。他们分别提供了以下方法。

字节输出流OutputStream

  1. 将指定字节写入此输出流。

    java 复制代码
    public abstract void write(int b) throws IOException
  2. 将指定字节数组中的b.length字节写入此输出流。

    java 复制代码
    public void write(byte b[]) throws IOException 
  3. 将指定字节数组中从偏移量off开始的len个字节写入此输出流。

    java 复制代码
    public void write(byte b[], int off, int len) throws IOException

字符输出流Writer

  1. 写入单个字符。

    java 复制代码
    public void write(int c) throws IOException
  2. 写入字符数组。

    java 复制代码
    public void write(char cbuf[]) throws IOException
  3. 写入字符数组的一部分。

    java 复制代码
    abstract public void write(char cbuf[], int off, int len) throws IOException

另外字符输出流是使用字符来操作数据 ,所以可以用字符串来代替字符数组 ,JDK还支持以下入参是字符串的方法。

  1. 写入一个字符串。

    java 复制代码
    public void write(String str) throws IOException
  2. 写入字符串的一部分。

    java 复制代码
    public void write(String str, int off, int len) throws IOException

4. 字节流和字符流区别

面试官:那字节流和字符流有什么区别?

有这些不同之处,主要是3个方面。

  • 基本单位不同。字节流以字节(8位二进制数)为基本单位来处理数据,字符流以字符为单位处理数据。
  • 使用场景不同 。字节流操作可以所有类型的数据,包括文本数据,和非文本数据如图片、音频等;而字符流只适用于处理文本数据。
  • 关于性能方面 。因为字节流不处理字符编码,所以处理大量文本数据时可能不如字符流高效;而字符流使用到内存缓冲区处理文本数据可以优化读写操作。

5. 转换流

面试官:你刚刚提到转换流把字节输入流转换成字符输入流,可不可以倒过来?

hhh,JDK没有提供这样的方法。

是这样的,虽然字节流比字符流的使用范围更广些 ,但字符流比字节流操作方便,所以字符流是一个很方便的流了,没有必要把一个方便的流转换成一个不方便的流。

未完待续。。。

好了,今天的分享就先到这,我们下期《Java IO系列》继续。

创作不易,不妨点赞、收藏、关注支持一下,各位的支持就是我创作的最大动力❤️

相关推荐
Bs_MoneyMagnet7 分钟前
基于springboot+vue的在线音乐管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
小番茄程序猿8 分钟前
Agent 工程化实测:p95 从 836ms 降到 12ms,而真正的收获是发现瓶颈根本不在 Agent 这层
后端
YangYang9YangYan9 分钟前
2026 校招管理会计 JD 拆解,数据分析能力要求与工具清单
java·数据库·数据分析
仍然.16 分钟前
SpringCloud---Seata
spring boot·后端·spring cloud
写后端的胖头鱼21 分钟前
【高频面试题】分布式锁在项目中的应用
java·分布式·后端·分布式锁·高频面试题
CoderYanger24 分钟前
Java EE 进阶:2.3 JavaScript
java·开发语言·前端·javascript·css·职场和发展·java-ee
凤山老林28 分钟前
Spring Boot + OpenSearch 实战:搞定全文检索、向量召回与混合排序
spring boot·后端·全文检索·向量·opensearch·全文索引
Wang's Blog35 分钟前
Java框架快速入门: Spring Security+OAuth2之前后端分离多模块工程配置
java·spring·状态模式
梅梅绵绵冰40 分钟前
SpringCloud网关
java·spring·spring cloud
敲代码的嘎仔1 小时前
互动问答系统实战:两级评论模型、ES 搜索集成、Caffeine 多级缓存全记录
java·开发语言·数据库·elasticsearch·缓存·mybatis·高并发