【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系列》继续。

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

相关推荐
oioihoii10 小时前
C++对象生命周期与析构顺序深度解析
java·开发语言·c++
IMPYLH10 小时前
Lua 的 tonumber 函数
开发语言·笔记·后端·junit·游戏引擎·lua
acethanlic10 小时前
配置 NeoVim 的代码折叠
后端
淡定__00910 小时前
.NET 中的异步编程:提升应用性能与响应能力
后端
BBB努力学习程序设计10 小时前
Java枚举(Enum):定义固定值的"类型安全"利器
java
我是天龙_绍10 小时前
为什么springboot依赖不写版本号?
后端
JuiceFS11 小时前
JuiceFS + MinIO:Ariste AI 量化投资高性能存储实践
运维·后端
It's now11 小时前
BeanRegistrar 的企业级应用场景及最佳实践
java·开发语言·spring
qq_5895681011 小时前
mybatis-plus和springboot项目错误记录
spring boot·后端·mybatis
毕设源码-赖学姐11 小时前
【开题答辩全过程】以 基于Java的小区物业管理系统APP的设计与实现为例,包含答辩的问题和答案
java·开发语言