系统学习 Java IO (一)----InputStream & OutputStream

目录:系统学习 Java IO ---- 目录,概览

InputStream

Java IO API中所有输入流的父类。
表示有序的字节流,换句话说,可以将 InputStream 中的数据作为有序的字节序列读取。
这在从文件读取数据或通过网络接收时非常有用。
InputStream 通常连接到某些数据源,如文件,网络连接,管道等
看如下代码片段:

public class InputStreamExample { public static void main(String[] args) throws IOException { InputStream inputStream = new FileInputStream("D:\\out.txt"); //do something with data... int data = inputStream.read(); while (data != -1) { System.out.print((char) data); data = inputStream.read(); } inputStream.close(); } }

注意:为了代码清晰,这里并没有考虑处理异常的情况,IO 异常处理有专门的介绍。

read()

此方法返回的是 int 值,其中包含读取的字节的字节值,可以将返回的 int 强制转换为 char 输出。
如果 read() 方法返回 -1 ,则表示已到达流的末尾,这意味着在 InputStream 中不再有要读取的数据。
也就是说,-1 作为 int 值,而不是 -1 作为字节或短值,这里有区别!

InputStream 类还包含两个 read() 方法,这些方法可以将 InputStream 源中的数据读入字节数组。
这些方法是:

int read(byte[]);

int read(byte[], int offset, int length);

一次读取一个字节数比一次读取一个字节要快得多,所以在可以的时候,使用这些读取方法而不是 read() 方法。

read(byte [])方法将尝试将尽可能多的字节读入作为参数给出的字节数组,因为数组具有空间。
该方法返回一个 int ,其值是实际读取了多少字节,这点和 read() 方法不一样。
如果可以从 InputStream 读取的字节少于字节数组的空间,则字节数组的其余部分将包含与读取开始之前相同的数据。例如:

InputStream input = new ByteArrayInputStream("123456789".getBytes()); byte[] bytes = new byte[4]; // 每次只读取 4 个字节 int data = input.read(bytes); while (data != -1) { System.out.print(new String(bytes)); data = input.read(bytes); }

将输出 123456789678 ,而不是预期的 123456789 !

因为第一次读取进 bytes 是 1234 ,第二次将是 5678 ,现在只剩下 9 一个数字了,注意此时 bytes 的值是 5678 ,然后再读取剩下 1个 9,不能装满 bytes 了,只能覆盖 bytes的第一个字节,最后返回的bytes 是 9678
所以记住检查返回的 int 以查看实际读入字节数组的字节数。

int read(byte[], int offset, int length);方法和 read(byte [])方法差不多,只是增加了偏移量和指定长度。
和 read() 一样,都是返回 -1 表示数据读取结束。
使用实例如下:

InputStream inputstream = new FileInputStream("D://out.txt"); byte[] data = new byte[1024]; int bytesRead = inputstream.read(data); while(bytesRead != -1) { doSomethingWithData(data, bytesRead); bytesRead = inputstream.read(data); } inputstream.close();

首先,此示例创建一个字节数组。
然后它创建一个名为 bytesRead 的 int 变量来保存每次读取 byte [] 调用时读取的字节数,
并立即分配 bytesRead 从第一次读取 byte [] 调用返回的值。

mark() and reset()

InputStream 类有两个名为 mark() 和 reset() 的方法,InputStream 的子类可能支持也可能不支持:

该子类覆盖 markSupported() 并返回true,则支持 mark( )和 reset() 方法。

该子类覆盖 markSupported() 并返回 false ,则不支持 mark() 和 reset() 。

该子类不重写 markSupported() 方法 ,则是父类的默认实现 public boolean markSupported() { return false; } 也是不支持 mark( )和 reset() 方法

mark() 在 InputStream 内部设置一个标记,默认值在位置 0 处。
可以手动标记到目前为止已读取数据的流中的点,然后,代码可以继续从 InputStream 中读取数据。
如果想要返回到设置标记的流中的点,在 InputStream 上调用 reset() ,然后 InputStream “倒退”并返回标记,
如此,便可再次从该mark点开始返回(读取)数据。很明显这可能会导致一些数据从 InputStream 返回多次。我来举个例子:

public static void testMarkAndReset() throws IOException { InputStream input = new ByteArrayInputStream("123456789".getBytes()); System.out.println("第一次打印:"); int count = 0;// 计算是第几次读取,将在第二次读取时做标记; byte[] bytes = new byte[3]; // 每次只读取 3 个字节 int data = input.read(bytes); while (data != -1) { System.out.print(new String(bytes)); if (++count == 2) { // 在第二轮读取,即读到数字 4 的时候,做标记 input.mark(16); // 从 mark 点开始再过 readlimit 个字节,mark 将失效 } data = input.read(bytes); } input.reset(); System.out.println("\n在经过 mark 和 reset 之后从 mark 位置开始打印:"); data = input.read(bytes); while (data != -1) { System.out.print(new String(bytes)); data = input.read(bytes); } }

将会输出:

第一次打印: 123456789 在经过 mark 和 reset 之后从 mark 位置开始打印: 789

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpysws.html