面向字节的输入输出流
本文最后更新于:2024年3月18日 凌晨
面向字节的输入输出流
面向字节的输入流
类InputStream介绍
- 面向字节的输入流类都是类
InputStream
的子类,如下图所示,类InputStream
是一个抽象类,定义了如下方法:public int read()
:读一个字节,返回读到字节的int
表示方式(0~255),读到流的末尾时返回-1public int read(byte b[])
:读多个字节到字节数组,返回结果为读到的实际字节个数,当输入流中无数据可读时返回-1public int read(byte[] b,int off,int len)
:从输入流读制定长度的数据到字节数组,数据从字节数组的off处开始存放,当输入流中无数据可读时返回-1public long skip(long n)
:指针跳过n个字节,定义输入位置指针的方法。public void mark()
:在当前位置指针处做一标记。public void reset()
:将位置指针返回标记处。public void close()
:关闭流。
- 数据的读取通常按照顺序逐个字节进行访问,在某些特殊情况下,要重复处理某个字节可通过
mark()
加标记,以后用reset()
返回该标记处再处理。
[例13-1]:将由键盘输入的一个十六进制数转换为十进制输出。
1 |
|
- 说明:任何一个数字字符与
0
字符之差就是其数字值,而a
,b
等字符则分别代表十进制10,11等数字,字符串拼接时注意是按十六进位的,所以拼接时将前面数字串的结果乘16再加上本位的结果。 - 思考:本程序是用逐个字符判别进行计算拼接的办法,实际上,有一种简单的办法,利用
Ineger.parseInt(String,16)
方法可将十六进制字符串准换为十进制的整数。
类InputStream的子类的使用
- 类
InputStream
的主要子类及功能如下表所示:
类名 | 构造方法的主要参数 | 功能描述 |
---|---|---|
ByteArrayInputStream | 字节数组 | 以程序中的一个字节数组作为输入源,通常用于对字节数组中的数据进行转换 |
FileInputStream | 类File的对象或字符串表示的文件名 | 以文件作为数据源,用于实现对磁盘文件中数据的读取 |
PipedInputStream | PipedOutputStream的对象 | 与另一输出管道相连,读取写入到输出管道中的数据,用于程序中线程间通信 |
FilterInputStream | InputStream的对象 | 用于修饰另一输出流以提供对输入数据的附加处理功能,其子类如下表所示 |
SequenceInputStream | 一系列InputStream的对象 | 将两个其他流首尾相连,合并为一个完整的输入流 |
ObjectInputStream | InputStream的对象 | 用于从输入流读取串行化对象,可实现轻量级对象持久性 |
- 其中过滤输入流类
FilterInputStream
是一个抽象类,没有提供实质的过滤功能,其子类中定义了具体的过滤功能,如下表所示:
类名 | 功能描述 |
---|---|
BufferedInputStream | 为所装饰的输入流提供缓冲区的功能,以提高输入数据的效率 |
DataInputStream | 为所装饰的输入流提供数据转换的功能,可从数据源读取各种基本类型的数据 |
LineNumberInputStream | 为文本文件输入流附加行号 |
PushbackInputStream | 提供回压数据的功能,可以多次读同样数据 |
- 以下结合数据操作访问单位的特点介绍若干流的使用。
以字节为单位读取数据
- 以文件访问操作为例,可利用文件输入流(FileInputStream)的方法从文件读取数据,注意,读到文件结尾时
read()
方法访问-1,编程时可以利用该特点来组织循环,从文件的第一个字节一直读到最后一个字节。
[例13-2]:在屏幕上显示文件内容。
1 |
|
- 说明:从命令行参数获取要显示的文件的文件名,利用
FileInputStream
的构造方法建立对文件进行操作的输入流,利用循环从文件逐个字节读取数据。将读到的数据转换为字符在屏幕上显示,运行程序不难发现,本程序可查看文本文件的内容,但如果输入的文件是二进制文件(如Java程序的class文件等)则看到的是乱码,因为那些文件中的数据不是字符,强制转换为字符是没有意义的。
以数据类型为单位读取数据
- 类
DataInputStream
实现了DataInput
接口,DataInput
接口规定了基本类型数据的读取方法,如readByte()
,readBoolean()
,readShort()
,readChar()
,readInt()
,readLong()
,readFloat()
,readDouble()
以及读取字符串的readUTF()
1 |
|
缓冲
- 在读取流的时候,一次读取一个字节并不是最高效的方法,很多流支持一次性读取多个字节到缓冲区,对于文件和网络流来说,利用缓冲区一次性读取多个字节效率往往要高很多,
InputStream
提供了两个重载方法来支持读取多个字节: int read(byte[] b)
:读取若干字节并填充到byte[]
数组,返回读取的字节数。int read(byte[] b, int off, int len)
:指定byte[]
数组的偏移量和最大填充数。- 利用上述方法一次读取多个字节时,需要先定义一个
byte[]
数组作为缓冲区,read()
方法会尽可能多地读取字节到缓冲区,但不会超过缓冲区的大小,read()
方法的返回值不再是字节的int
值,而是返回实际读取了多少个字节,如果返回-1
,表示没有更多的数据了。 - 利用缓冲区一次读取多个字节的代码如下:
1 |
|
面向字节的输出流
- 面向字节的输入流都是类
OutputStream
的后代类,如下图所示,类OutputStream
是一个抽象类,含一套所有输出流均需要的方法。public void write(int b)
:将参数b的低字节写入输出流。public void write(byte[] b)
:将字节数组全部写入输出流。public void flush()
:强制将缓冲区数据写入输出流对应的外设。public void close()
:关闭输出流。
- 其中,
PrintStream
提供了常用的print()
,println()
,printf()
等方法。
以字节为单位的数据写入
[例13-3]:将一个大文件分拆为若干小文件。
1 |
|
- 说明:运行程序需要两个参数,一个是要分拆的大文件名,另一个是小文件的大小,分拆的小文件命名为file0,file1,…
- 注意:将数据写入文件用
write(b,0,byteRead)
方法是保证将当前读到的数据写入文件,不能直接用write(b)
,因为最后读的子文件通常会更少。
以数据类型为单位写入数据
- 类DataOutputStream实现各种基本类型数据的输出处理,它实现了
DataOutput
接口,在该接口中定义了基本类型数据的输出方法,如writeByte(int)
,writeBytes(String)
,writeBoolean(boolean)
,writeChars(String)
,writeInt(int)
,writeLong(long)
,writeFloat(float)
,writeDouble(double)
,writeUTF(String)
等。 - 以下结合一个文件写入的例子演示基本类型数据的读写访问处理。
[例13-4]:找出10~100之间的所有姐妹素数,写入到文件中,所谓姐妹素数是指相邻两个奇数均为素数。
1 |
|
- 注意:用记事本查看文件将显示乱码,原因在于该文件中的数据不是文本格式的数据,要读取其中的数据需要以输入流的方式访问文件,用
DataInputStream
的readInt()
方法读取对应数据,以下为程序代码:
1 |
|
注意
- 本程序在处理文件访问中利用了异常处理机制,在try块中用无限循环来读取访问文件,如果遇到文件结束将抛出
EOFException
异常。 - 从上面的例子可以看出,各种过滤流实际上是对数据进行特殊的包装处理,在读写字节的基础上提供更高级的功能,从而更方便地访问数据。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!