Java标准I/O知识体系图:

java代码文件转换字节流 java 字节流转文件_读取文件


java代码文件转换字节流 java 字节流转文件_写入文件_02


java代码文件转换字节流 java 字节流转文件_写入文件_02

I/O 是Input/Output(输入、输出)的简称,输入流可以理解为向内存输入,输出流是从内存输出。

2、流

流是一个连续的数据流,可以从流中读取数据,也可以往流中写数据。流与数据源,或数据源流向的媒介相关联。

在Java IO流中,流可以是字节流,也可以是字符流。

3、Java I/O 用途与对应的流一览


java代码文件转换字节流 java 字节流转文件_java代码文件转换字节流_04

注:粗体为节点流。蓝色为转换流(字节流转为字符流)。

4、流的处理

流分节点流和处理流两种。

节点流:可以从或向一个特定的地方(节点)读写数据。如FileInputStream、FileReader。

处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接

5、文件访问

(1)读取文件

如果你需要在不同端使用读取文件,你可以根据你要读的文件是二进制文件还是文本文件,或者根据你要处理的数据是准备采取字节方式还是字符方式,决定使用 FileInputStream 或者 FileReader。两者支持你从文件开头开始到文件结尾读取一个字节或者字符,也可以将读取的多个字节或字符,写入到内存的字节数组或字符数组。

单字节读取文件示例:

java代码文件转换字节流 java 字节流转文件_读取文件_05

字节数组读取文件示例:

java代码文件转换字节流 java 字节流转文件_java代码文件转换字节流_06

单字符读取文件示例:

java代码文件转换字节流 java 字节流转文件_写入文件_07

字符数组读取文件示例:

java代码文件转换字节流 java 字节流转文件_字符流转字节流_08

(2)写入文件

与读取文件类似:

如果你需要在不同端使用写入文件,你可以根据你要写的文件是二进制文件还是文本文件,或者根据你要处理的数据是准备采取字节方式还是字符方式,决定使用 FileOutputStream 或者 FileWriter。两者支持你可以一次写入一个字节或者字符到文件中,也可以直接写入一个字节数组或者字符数据。数据按照写入的顺序存储在文件当中。

单字节写入文件示例:


java代码文件转换字节流 java 字节流转文件_java代码文件转换字节流_09

字节数组写入文件示例:


java代码文件转换字节流 java 字节流转文件_字符流转字节流_10

单字符写入文件示例:

java代码文件转换字节流 java 字节流转文件_读取文件_11

字符数组写入文件示例:


java代码文件转换字节流 java 字节流转文件_写入文件_12

(3)随机访问文件

如果你需要不按特定的存取顺序,随意读取或者写入文件,可以考虑RandomAccessFile。

void seek(long pos) 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。

简单示例:

java代码文件转换字节流 java 字节流转文件_写入文件_13

6、管道(线程内存)

管道为同一JVM中运行的线程提供基于内存的通信机制。但是你不能利用管道在不同的JVM中的线程间通信。


java代码文件转换字节流 java 字节流转文件_输入流_14

在概念上,Java的管道不同于Unix/Linux系统中的管道。在Unix/Linux中,运行在不同地址空间的两个进程可以通过管道通信。在Java中,通信的双方应该是运行在同一进程中的不同线程。当然除了管道之外,一个JVM中不同线程之间还有许多通信的方式。实际上,线程在大多数情况下会传递完整的对象信息而非原始的字节数据。但是,如果你需要在线程之间传递字节数据,Java IO的管道是一个不错的选择。

当使用两个相关联的管道流时,务必将它们分配给不同的线程。read()方法和write()方法调用时会导致流阻塞,这意味着如果你尝试在一个线程中同时进行读和写,可能会导致线程死锁。

简单示例:

java代码文件转换字节流 java 字节流转文件_读取文件_15

7、序列化与ObjectInputStream、ObjectOutputStream

使用ObjectInputStream、ObjectOutputStream读取或写入对象,首先该对象必须实现Serializable接口,使得能够序列化和反序列化。

简单示例:

java代码文件转换字节流 java 字节流转文件_输入流_16

8、回推流:PushbackInputStream与PushbackReader

PushbackInputStream/PushbackReader 用于解析InputStream/Reader内的数据,允许你读取字节/字符后,回推(pushback)到流中,而不破坏流。

PushbackInputStream类具有以下构造函数:


java代码文件转换字节流 java 字节流转文件_写入文件_17

第一种形式创建的流对象允许将一个字节返回到输入流; 第二种形式创建的流对象具有一个长度为numBytes的回推缓存,从而允许将多个字节回推到输入流中。

提供了unread()方法,如下所示:

java代码文件转换字节流 java 字节流转文件_读取文件_18

第一种形式回推b的低字节,这会使得后续的read()调用会把这个字节再次读取出来。第二种形式回推buffer中的字节。第三种形式回推buffer中从offset开始的numBytes个字节。当回推缓存已满时,如果试图回推字节,就会抛出IOException异常。

示例:

java代码文件转换字节流 java 字节流转文件_java代码文件转换字节流_19

注:PushbackInputStream对象会使得InputStream对象(用于创建PushbackInputStream对象)的mark()或reset()方法无效。对于准备使用mark()或reset()方法的任何流来说,都应当使用markSupported()方法进行检查。

9、行数记录:LineNumberInputStream与LineNumberReader

LineNumberInputStream与LineNumberReader提供跟踪行号的附加功能。行是以回车符 (‘’)、换行符 (‘’) 或回车符后面紧跟换行符结尾的字节序列。在所有这三种情况下,都以单个换行符形式返回行终止字符。 行号以 0 开头,并在 read 返回换行符时递增 1。

使用getLineNumber()可以获取当前读取所在行数。

示例:

java代码文件转换字节流 java 字节流转文件_java代码文件转换字节流_20

10、StreamTokenizer的使用

StreamTokenizer定义了几种基本的常量用于标识解析过程:TT_EOF(流结尾)、TT_EOL(行结尾)、TT_NUMBER(数字符号, 0 1 2 3 4 5 6 7 8 9 . -都属于数字语法)、TT_WORD(一个单词)。

ttype 在调用 nextToken 方法之后,此字段将包含刚读取的标记的类型。

nval 如果当前标记是一个数字,则此字段将包含该数字的值。

sval 如果当前标记是一个文字标记,则此字段包含一个给出该文字标记的字符的字符串。


java代码文件转换字节流 java 字节流转文件_输入流_21

基本方法介绍一下:

nextToken() – 从此标记生成器的输入流中解析下一个标记。

(1)标记注释

commenChar(int ch) – 指定某个字符为注释字符,此字符之后直到行结尾都被stream tokenizer忽略。
slashSlashComments(boolean flag) – 如果为true,则/*与*/之间的都被认为是注释,反之,不是。
slashStartComments(boolean flag) – 如果为true,则//之后到行结尾的所有都被认为是注释,反之,不是。

(2)基本语义

eolIsSignificant(boolean flag) – 决定一个行结束符是否被当作一个基本的符号处理,如果是true,则被当作一个基本符号,不当作普通的分隔符,如果是false,则保持原义,即当作普通的分隔符。
lowerCaseMode(boolean flag) – 决定是否读取一个单词时是否转变成小写。
parseNumbers() – 当stream tokenizer遭遇到一个单词为双精度的浮点数时,会把它当作一个数字,而不是一个单词。
resetSyntax() – 重置语法表使所有的字符都被认为是“ordinary”。

(3)指定字符语义

ordinaryChar(int ch) – 指定字符在这个tokenizer中保持原义,即只会把当前字符认为普通的字符,不会有其他的语义。
ordinaryChars(int low, int hi) – 指定范围内的字符保持语义,同上
whitespaceChars(int low, int hi) – 字符low与hi之间的所有字符都被当作为空格符,即被认识为tokenzier的分隔符。
wordChars(int low, int hi) – 字符low与hi之间的所有字符都被当作为单词的要素。一个单词是由一个单词要素后面跟着0个或者更多个单词要素或者数字要素。

11、合并流SequenceInputStream

SequenceInputStream会将与之相连接的流集组合成一个输入流并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的末尾为止。 合并流的作用是将多个源合并合一个源。


java代码文件转换字节流 java 字节流转文件_java代码文件转换字节流_22