面向字节的输入输出流
本文最后更新于: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 协议 ,转载请注明出处!
