大家好,我是IT修真院北京分院第27期的JAVA学员,一枚正直纯洁善良的java程序员。
今天给大家分享一下,修真院官网Java任务10,深度思考中的知识点———什么是IO流?
1.背景介绍
什么是流
流就是一系列的数据
当不同的介质之间有数据交互的时候,JAVA就使用流来实现。 数据源可以是文件,还可以是数据库,网络甚至是其他的程序。 比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流。 输入流: InputStream 输出流:OutputStream
文件输入流
如下代码,就建立了一个文件输入流,这个流可以用来把数据从硬盘的文件,读取到JVM(内存)。 目前代码只是建立了流,还没有开始读取。
package stream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestStream {
public static void main(String[] args) {
try {
File f = new File("d:/lol.txt");
// 创建基于文件的输入流
FileInputStream fis = new FileInputStream(f);
// 通过这个输入流,就可以把数据从硬盘,读取到Java的虚拟机中来,也就是读取到内存中
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
--如图:
标题
2.知识剖析
字节流
InputStream字节输入流 OutputStream字节输出流 用于以字节的形式读取和写入数据
ASCII码 概念
所有的数据存放在计算机中都是以数字的形式存放的。 所以字母就需要转换为数字才能够存放。 比如A就对应的数字65,a对应的数字97. 不同的字母和符号对应不同的数字,就是一张码表。 ASCII是这样的一种码表。 只包含简单的英文字母,符号,数字等。 不包含中文,德文,俄语等复杂的。
字符 | 十进制数字 | 十六进制数字 |
! | 33 | 21 |
" | 34 | 22 |
# | 35 | 23 |
$ | 36 | 24 |
% | 37 | 25 |
& | 38 | 26 |
' | 39 | 27 |
( | 40 | 28 |
) | 41 | 29 |
* | 42 | 2A |
+ | 43 | 2B |
, | 44 | 2C |
- | 45 | 2D |
. | 46 | 2E |
/ | 47 | 2F |
48 | 30 | |
1 | 49 | 31 |
2 | 50 | 32 |
3 | 51 | 33 |
4 | 52 | 34 |
5 | 53 | 35 |
6 | 54 | 36 |
7 | 55 | 37 |
8 | 56 | 38 |
9 | 57 | 39 |
: | 58 | 3A |
; | 59 | 3B |
< | 60 | 3C |
= | 61 | 3D |
> | 62 | 3E |
@ | 64 | 40 |
A | 65 | 41 |
B | 66 | 42 |
C | 67 | 43 |
D | 68 | 44 |
E | 69 | 45 |
F | 70 | 46 |
G | 71 | 47 |
H | 72 | 48 |
I | 73 | 49 |
J | 74 | 4A |
K | 75 | 4B |
L | 76 | 4C |
M | 77 | 4D |
N | 78 | 4E |
O | 79 | 4F |
P | 80 | 50 |
Q | 81 | 51 |
R | 82 | 52 |
S | 83 | 53 |
T | 84 | 54 |
U | 85 | 55 |
V | 86 | 56 |
W | 87 | 57 |
X | 88 | 58 |
Y | 89 | 59 |
Z | 90 | 5A |
[ | 91 | 5B |
\ | 92 | 5C |
] | 93 | 5D |
^ | 94 | 5E |
_ | 95 | 5F |
` | 96 | 60 |
a | 97 | 61 |
b | 98 | 62 |
c | 99 | 63 |
d | 100 | 64 |
e | 101 | 65 |
f | 102 | 66 |
g | 103 | 67 |
h | 104 | 68 |
i | 105 | 69 |
j | 106 | 6A |
k | 107 | 6B |
l | 108 | 6C |
m | 109 | 6D |
n | 110 | 6E |
o | 111 | 6F |
p | 112 | 70 |
q | 113 | 71 |
r | 114 | 72 |
s | 115 | 73 |
t | 116 | 74 |
u | 117 | 75 |
v | 118 | 76 |
w | 119 | 77 |
x | 120 | 78 |
y | 121 | 79 |
z | 122 | 7A |
{ | 123 | 7B |
| | 124 | 7C |
} | 125 | 7D |
~ | 126 | 7E |
--
以字节流的形式读取文件内容
InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。 FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取
以字节流的形式向文件写入数据
OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。 FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据 注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。 但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常
数据流
DataInputStream 数据输入流 DataOutputStream 数据输出流
直接进行字符串的读写
使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写 如本例,通过DataOutputStream 向文件顺序写出 布尔值,整数和字符串。 然后再通过DataInputStream 顺序读入这些数据。 注: 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。
对象流
对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘 一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口
序列化一个对象
把一个对象序列化有一个前提是:这个对象的类,必须实现了Serializable接口
字符流
Reader字符输入流 Writer字符输出流 专门用于字符的形式读取和写入数据
使用字符流读取文件
FileReader 是Reader子类,以FileReader 为例进行文件读取
使用字符流把字符串写入到文件
FileWriter 是Writer的子类,以FileWriter 为例把字符串写入到文件
缓存流
以介质是硬盘为例,字节流和字符流的弊端: 在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。 为了解决以上弊端,采用缓存流。 缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。 就好比吃饭,不用缓存就是每吃一口都到锅里去铲。用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲 缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作。
使用缓存流读取数据
缓存字符输入流 BufferedReader 可以一次读取一行数
使用缓存流写出数据
PrintWriter 缓存字符输出流, 可以一次写出一行数据
FLUSH方法
有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush
3.常见问题
如何关闭流
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展
4.解决方案
- 在try中关闭
在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端; 如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用
- 在finally中关闭
这是标准的关闭流的方式 1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally. 2. 在finally关闭之前,要先判断该引用是否为空 3. 关闭的时候,需要再一次进行try catch处理 这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦
- 使用try()的方式
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭 这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术 所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源
5.编码实战
详见视频
https://v.qq.com/x/page/z0767my4wju.html?pcsharecode=VbuMUEue&sf=uri
6.扩展思考
SYSTEM.IN使用
System.out 是常用的在控制台输出数据的 System.in 可以从控制台输入数据
使用SYSTEM.IN.READ虽然可以读取数据,但是很不方便。使用SCANNER就可以逐行读取了
7. 参考文献
how2j.cn: http://how2j.cn/k/io/io-system-in/352.html#nowhere
8. 更多讨论
Q1:io流的存储位置和流向问题?
A1:IO流一般是以内存为基准,我们的IO流最开始是在jvm中,然后流向硬盘。
Q2:IO流传输时,是以文件为单位传输,还是以文件内字节或字符依次传输?
A2:两种情况都有,只是进行文件传输时候,会产生垃圾数据,锟斤拷
Q3:中文问题?
A3:工作后经常接触的编码方式有如下几种:
ISO-8859-1 ASCII 数字和西欧字母
GBK GB2312 BIG5 中文
UNICODE (统一码,万国码)
其中
ISO-8859-1 包含 ASCII
GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文。
UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中
今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖~