读写字节、完整的流家族、组合输入/输出流过滤器——输入/输出流

读写字节

InputStream 类有一个抽象的方法: abstract int read(); 这个方法读入一个字节,并返回读入的字节,或者在遇到输入源结尾时返回 -1。在设计具体的输入流类时,必须覆盖这个方法以提供适用的功能。
OutStream 类定义了下面的抽象方法: abstract void write(int b); 可以向某个输出位置写出一个字节。
read 和 write 方法在执行时都将阻塞,直至字节确实被读入或写出。这就意味着如果流不能被立即访问,那么当前的线程将被阻塞。这使得在这两个方法不能使用的时间里,其他线程就有机会去执行工作。
available 方法使我们可以检查当前可读入的字节数量,这意味着下面的代码就不可能被阻塞:

int bytesAvailable = in.available();
if (bytesAvailable > 0){
	byte[] data = new byte[bytesAvailable[;
	in.read(data);
}

当完成对输入/输出流的读写时,应该通过调用 close 方法来关闭它,这个调用会释放掉十分有限的操作系统资源。如果一个应用程序打开了过多的输入/输出流而没有关闭,那么系统资源将会被耗尽。关闭一个输出流的同时还会冲刷用于该输出流的缓冲区:这样就会使得更大的包在关闭输出流时都将被送出。特别是,如果不关闭文件,那么最后一个包可能永远也得不到传递。当然,也可以用flush来人为地冲刷这些输出。

java.io.InputStream
  • abstract int read()
    从数据中读入一个字节,并返回该字节。这个 read 方法在碰到输入流的结尾时返回 -1。
  • int read(byte[] b)
    读入一个字节数组,并返回实际读入的字节数,或者在碰到输入流的结尾时返回 -1.这个 read 方法最多读入 b.length 个字节
  • int read(byte[] b, int off, int len)
    读入一个字节数组。这个方法返回实际读入的字节数,或者在碰到输入流的结尾使返回 -1.
    b : 数据读入的数组
    off :第一个读入字节应该被放置的位置在 b 中的偏移量
    len : 读入字节的最大数量
  • long skip(long n)
    在输入流中跳过 n 个字节,返回实际跳过的字节数(如果碰到输入流的结尾,则可能小于 n)
  • int available()
    返回在不阻塞的情况下可获取的字节数(意味着当前线程将失去它对资源的占用——不知道什么意思)
  • void close()
    关闭这个输入流
  • void mark(int readlimit)
    在输入流的当前位置打一个标记(不是所有流都支持)。如果输入流中已经读入的字节多于readlimit个,则这个流允许忽略这个标记。
  • void reset()
    返回到最后一个标记,随后对 read 的调用将重新读入这些字节。如果当前没有任何标记,则这个流不被重置
  • boolean markSupported()
    如果这个流支持打标记,则返回true
java.io.OutputStream
  • abstract void write(int n)
    写出一个字节的数据
  • void write(byte[] b)
  • void write(byte[] b, int off, int len)
    写出所有字节或某个范围的字节到数组 b 中
    b :数据写出的目标数组
    off :第一个写出字节在 b 中的偏移量
    len :写出字节的最大数量
  • void close()
    冲刷并关闭输出流
  • void flush()
    冲刷输出流,也就是将所有缓冲的数据发送到目的地

完整的流家族

略~~


组合输入/输出流过滤器

FileInputStream 和 FileOutputStream 可以提供附着在一个磁盘文件上的输入流和输出流,而只需要想起提供文件名或文件的完整路径。例如:
FileInputStream fin = new FileInputStream("employee.dat");
这行代码可以查看在用户目录下名为 “employee.dat” 的文件。

FileInputSream没有任何读入数值类型的方法,DataInputStream也没有任何从文件中获取数据的方法。因此,需要对二者进行结合。例如:为了从文件中读入数字,首先需要创建一个FileInputStream,然后将其传递给DataInputStream的构造器:

FileInputStream fin = new FileInputStream("employee.dat");
DataInputStream din = new DataInputStream(fin);
double x = din.readDouble();

输入流在默认情况下是不被缓冲区缓存的,也就是说,每次对read的调用都会请求操作系统再分发一个字节。相比之下,请求一个数据块并将其置于缓冲区中会显得更加高效。如果想用缓冲机制,以及用于文件的数据输入方法,就要用下面的构造器序列:

DataInputStream din = new DataInputStream(
					  new BufferedInputStream(
					  new FuleInputStream("employee.dat")));

DataInputStream置于构造器最后,是希望它们能够使用带缓冲机制的read方法。
当多个输入流连接在一起时,需要跟踪各个中介输入流。当读入输入时,需要预览下一个字节,以便了解它是否为我们需要的值:

PushbackInputStream pbin = new PushbackInputStream(
						   new BufferedInputStream(
						   new FileInputStream("employee.dat")));

可以预读下一个字节:int b = pbin.read();
并且可以判断是否为你所期望的值:if (b != '<') pbin.unread(b);

但是,读入和退回是可应用于可回退输入流的仅有的方法。如果希望能够预先浏览并且还可以读入数字,就需要一个既是可回退输入流,又是一个数据输入流的引用:

DataInputStream din = new DataInputStream(
			   pbin = new PushbackInputStream(
					  new BufferedInputStream(
					  new FileInputStream("employee.dat")));

可以从一个ZIP压缩文件中通过使用下面输入流序列来读入数字:

ZipInputStream zin = new ZipInputStream(new FileInputStream("employee.zip"));
DataInputStream din = new DataInputStream(zin);
  • FileInputStream(File file)
    使用由 name 字符串或file对象指定路径名的文件创建一个新的文件输入流
  • FileOutputStream(File file, boolean append)
    使用由 name 字符串或file对象指定路径名的文件创建一个新的文件输出流。如果append参数为 true ,数据将被添加到文件尾,而具有相同名字的已有文件不会被删除;否则,这个方法会删除所有具有相同名字的已有文件
  • BufferedInputStream(InputStream in)
    创建一个带缓冲区的输入流。带缓冲区的输入流在从流中读入字符时,不会每次都对设备访问。当缓冲区为空时, 会向缓冲区中读入一个新的数据块
  • BufferedOutputStream(OutputStream out)
    创建一个带缓冲区的输出流。带缓冲区的输出流在收集要写出的字符时,不会每次都对设备访问。当缓冲区填满或当流被冲刷时,数据就被写出
  • PushbackInputStream(InputStream in, int size)
    构建一个可以预览一个字节或者具有制定的回退缓冲区的输入流
  • void unread(int b)
    回退一个字节,可以在下次调用read时再次获取
    b :要再次读入的字节
发布了176 篇原创文章 · 获赞 46 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43207025/article/details/104373325