| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 高薪程序员&面试题精讲系列22之说说Java的IO流,常用哪些IO流? -> 正文阅读 |
|
[Java知识库]高薪程序员&面试题精讲系列22之说说Java的IO流,常用哪些IO流? |
一. 面试题及剖析1. 今日面试题今天 壹哥 带各位复习一块可能会令初学者比较头疼的内容,起码当时让我很有些头疼的内容,那就是I/O流。为啥I/O流会让很多初学者头疼呢?其实主要是因为I/O流的分类实在是太多了,一会是输入流,一会是输出流,还有字节流、字符流、文件输入流,文件输出流,缓冲流.....乱七八糟一大堆,光是这些英文单词把人背的脑袋都大了。 正因为如此,面试官就喜欢在这里考察我们的Java基础,常见的I/O流题目如下:
2. 题目剖析我们在开发时,用到I/O流的地方有很多,比如文件的上传下载,数据传输、存储,音视频编解码操作等,这些都是很重要的操作,所以面试官就很喜欢考察我们这一块的基础是否扎实。如果我们I/O流的基础不够扎实,就很难写出健壮高效的偏底层代码。 所以接下来 壹哥 会带各位详细全面的梳理一下I/O流的内容,以后再遇到有关I/O流的面试题,直接把本博客中的内容甩到面试官脸上即可,HIA HIA。 二. I/O流1. 概念首先 壹哥 来解释一下 “I/O流” 这个概念,如果我们连 I/O流 是个啥都不知道,也就没必要继续往下看了。在这里 壹哥 会从两部分展开介绍I/O流,即 “I/O” 与 “流”。 1.1 I/O I/O中间用 “/”斜杠 分割,其实代表的是两个内容,即 “I” 与 “O”,分别是 “In” 与 “Out” 的缩写。
1.2 流 接下来咱们再来看看什么是 “流”!请先在脑海里想一下,“流”是一种什么样的形态?其实Java中各个API的命名都是很形象的,绝对都做到了见名知意。 这里 “流” 就是一个很形象的概念!当我们的代码程序需要 读入数据 的时候,可以开启一个连通 数据源 的流(输入流),这个数据源可以是文件、内存、数据库,或是网络连接。同样的,当我们的代码程序需要 输出数据 的时候,可以开启一个连通 目的地 的流(输出流),这个目的地一般是指我们的代码程序。这时候你可以想象一下,我们的数据好像就在数据源与目的地之间 “流动” 起来了一样。 其实 流(stream)这个概念,一开始源于UNIX中的管道(pipe)概念。在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备、外部文件等。 最后 壹哥 再给各位提取一下流的概念:
2. 作用而且从上面我对I/O流的描述中,我们也可以抽取出I/O流的核心作用,如下:
一言以蔽之,I/O流屏蔽了实际的I/O设备中处理数据的各种细节,我们不必关心其内部具体的流动过程,只需知道I/O流可以用来处理设备之间的数据传输即可。 3. 分类如果只看上面关于I/O流的概念,感觉也并没有什么难度,但是对I/O流的学习,最难的是在于其分类实在是太多。I/O流中有着不同的划分维度,如果我们根据这些不同的标准来分类的话,可以分类如下: 接下来 壹哥 再分别对这3种分类进行详解一下。 3.1 输入流与输出流 从I/O流的流动方向上,我们知道I/O流其实可以分为输入流与输出流,但是不少初学者总是分不清输入流与输出流,甚至会把两者搞反。所以接下来 壹哥 就再明确一下输入流与输出流的区别,我们来看下图: 在上图中,我们以家中自来水的进水与出水来形象的比喻输入流与输出流。
壹哥 再把上图中的各角色明确一下:
所以,I/O流中的输入流与输出流,入与出都是相对于内存而言的。从某个数据源读取数据到内存中,被称为输入流;从内存中把数据持久化保存到其他设备上,则被称为输出流。简单一句话,流向内存是输入流,流出内存的输出流。我们再来看下图: 另外要注意,我们可以从输入流中读取信息,但不能对它写;可以对输出流进行写操作,但不能从中读。所以输入也叫做读取数据,输出也叫做作写出数据! 至此,你应该不会再把输入流和输出流搞反了吧,是不是应该给 壹哥 点个赞,hiahia...... 3.2 字节流与字符流 上面 壹哥 说了,按照数据流的数据单位不同,I/O流可以分为字节流与字符流,两者的区别如下:
这是因为在Java中,一个字节的空间是1个Byte,即8位;而一个字符的空间是2个Byte,即16位。另外Java的字节是有符号类型,字符是无符号类型! 另外我们要知道,在计算机里,一切文件数据(文本、图片、视频等)在存储时,都是以二进制的形式保存的,即都是一个一个的字节,在传输时也一样如此。所以,字节流可以传输任意类型的文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。 但是因为数据编码的不同,为了对字符进行高效的操作,就有了字符流。字符流的本质其实也是基于字节流,在进行读取时去查了指定的码表,而字节流直接读取数据会有乱码的问题(读中文会乱码)。 所以字节流和字符流的原理其实也是相同的,只不过处理的数据单位大小不同而已。一般在Java关于I/O流的API里,后缀是Stream的是字节流,而后缀是Reader和Writer的是字符流。 你可能会问,我们开发时,到底是该选择字节流还是字符流呢? 对于字节流和字符流,如果我们只是要处理纯文本数据,可以优先考虑字符流。 除此之外尽量使用字节流。 3.3 节点流与处理流 另外如果从I/O流的功能角度来看,I/O流可以分为节点流和处理流,两者区别如下: 节点流:直接与数据源相连,读入或写出。 但是如果我们直接使用节点流进行操作,读写并不方便,所以为了更快的读写文件,才有了处理流。 处理流:一般会与节点流一起使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。 4. I/O流相关API在Java中,关于I/O流的API,共有四大类,分别如下:
即Java中字节流的抽象基类有如下2个: InputStream,OutputStream InputStream与OutputStream类关系如下图所示: 字符流的抽象基类有如下2个: Reader,Writer Reader与Writer类关系如下图所示: 我们可以用下图概括展示: 由这四个基类派生出来的子类名称,都是以其父类名作为子类名的后缀,如InputStream的子类FileInputStream,Reader的子类FileReader。 4.1 InputStream字节输入流 InputStream的常用方法: int available() 从下一次调用此输入流的方法返回可从该输入流读取(或跳过)的字节数,而不会阻塞。 void close() 关闭此输入流并释放与流相关联的任何系统资源。 void mark(int readlimit) 标记此输入流中的当前位置。 boolean markSupported() 测试此输入流是否支持 mark和 reset方法。 abstract int read() 从输入流读取数据的下一个字节。 int read(byte[] b) 从输入流中读取一些字节数,并将它们存储到缓冲器阵列 b。 int read(byte[] b, int off, int len) 从输入流读取最多 len个字节的数据到字节数组。 byte[] readAllBytes() 从输入流读取所有剩余字节。 int readNBytes(byte[] b, int off, int len) 将所请求的字节数从输入流读入给定的字节数组。 void reset() 将此流重新定位到最后在此输入流上调用 mark方法时的位置。 long skip(long n) 跳过并丢弃来自此输入流的 n字节的数据。 long transferTo(OutputStream out) 从该输入流中读取所有字节,并按读取的顺序将字节写入给定的输出流。 4.2 OutputStream字节输出流 OutputStream字节输出流的方法: void close() 关闭此输出流并释放与此流相关联的任何系统资源。 void flush() 刷新此输出流并强制任何缓冲的输出字节被写出。 void write(byte[] b) 将 b.length字节从指定的字节数组写入此输出流。 void write(byte[] b, int off, int len) 从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。 abstract void write(int b) 将指定的字节写入此输出流。 4.3 Reader字符输入流 Reader主要方法如下: abstract void close() 关闭流并释放与之相关联的任何系统资源。 void mark(int readAheadLimit) 标记流中的当前位置。 boolean markSupported() 告诉这个流是否支持mark()操作。 int read() 读一个字符 int read(char[] cbuf) 将字符读入数组。 abstract int read(char[] cbuf, int off, int len) 将字符读入数组的一部分。 int read(CharBuffer target) 尝试将字符读入指定的字符缓冲区。 boolean ready() 告诉这个流是否准备好被读取。 void reset() 重置流。 long skip(long n) 跳过字符 4.4 Writer字符输出流 Writer的主要方法如下: Writer append(char c) 将指定的字符附加到此writer Writer append(CharSequence csq) 将指定的字符序列附加到此writer Writer append(CharSequence csq, int start, int end) 将指定字符序列的子序列附加到此writer abstract void close() 关闭流,先刷新 abstract void flush() 刷新流 void write(char[] cbuf) 写入一个字符数组。 abstract void write(char[] cbuf, int off, int len) 写入字符数组的一部分 void write(int c) 写一个字符 void write(String str) 写一个字符串 void write(String str, int off, int len) 写一个字符串的一部分 4.5 完整API图 以上这些java.io包中的API,我给大家绘制了下图: 从上图中,我们可以看到,有各种各样的I/O流相关的API类,我们可以简单归纳并做如下简介:
三. 参考答案1. Java中的I/O流有哪些回到我们的面试题上面来,Java中的I/O流有哪些,其实用下图即可回答。 2. 常用I/O有哪些我们知道,Java中的I/O流有很多,但是开发时并不是每一个都经常用到的,所以 壹哥 用下图给各位展示了常用的I/O流,下图中凡是带有中文解释的I/O流,基本就是我们开发时最常用的。 四. 结论最后我们把IO流再简单总结一下。 1. 哪些流可以提高读写性能?
2. Java有几种类型的流?3. Java中I/O流相关API
Java中其他各种流都是由它们派生出来的。 4. 操作文本文件用什么I/O流?
5. 操作基本数据类型和String类型用什么流?
6. 哪些I/O流可以指定字符编码?
7. 各I/O流API作用
8. 开发时到底该选择哪种流?我们现在已经知道了这么多的 I/O流 分类,那在开发时该选择使用哪种呢?什么时候用输出流?什么时候用字节流?我们可以根据下面三步选择适合自己的流:
至此,壹哥 就把I/O流中的核心内容带大家都复习了一下,当然还有挺多细节没有总结到位,毕竟我这里是面试题梳理总结,不是专门的I/O流教程,请各位再结合之前学习I/O流时的内容,形成自己的知识脉络。如果你有什么想法,可以在评论区留言讨论哦。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 1:33:58- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |