The Java Programming Language, 4th Edition. Chapter 20.2 [翻译]

[b]20.2 Byte Streams[/b]
java.io包为基本的字节输入/输出流定义了抽象类。这些抽象类被扩展用于支持其它一些有用的流类型。流类型基本成对出项:比如,FileInputStream用来读取一个文件, FileOutputStream用于写入一个文件。

在你学习具体的输入/输出字节流前,有必要了解一下InputStream和OutputStream抽象类。
图20-1描述了字节流类的继承体系。

所有的字节流类存在某些共性。比如,所有的流类都支持"打开"或"关闭"。当你创建一个流时,你就打开了它。当它是打开的时候,你就可以读取或者写入。你可以调用close方法关闭一个流,这个方法是Closeable接口的方法。关闭一个流将释放资源(比如文件句柄)。一个流类可以定义一个finalize方法,当垃圾回收时来释放这些资源。但是有时,这样释放资源可能为时已晚。你应该使用完一个流后就将它关掉。

所有的字节流类都采取相同的同步策略和并行行为,20.5将讲述这些。

20.2.1 InputStream
抽象类InputStream申明了一些方法用于从某个特殊的源读取字节。在java.io中InputStream是多数字节输入流的父类,它定义了下列
方法:


public abstract int read() throws IOExcepiton

读取一个字节,并将其作为一个介于0到255之间的整数返回。换句话说,这个字节值被转换为一个无符号整型。如果没有可用的字节了,也就是说到达了文件结尾,返回的值是-1。这个方法将被阻塞,除非可用的字节,或到达文件尾,或者异常发生。read方法返回int类型,而不是byte类型是因为该方法需要返回所有的合法byte值和一个用来标识流结束符的标志量。byte类型就显得小了,所以选用int类型。


public int read(byte[] buf, int offset, int cout) thorws IOException

读取到一个字节数组中。读入字节数组的最大数目是count。从buf[offset]开始放置读入的字节,最多到buf[offset+count-1]。数组中其它位置的值不变。返回实际读入的字节数。如果因为到达文件结尾,没有字节读入,就返回-1。如果count设为0,也就是没有字节被读入,那么返回0。如果不是因为到达流末尾,而是其它原因造成第一个字节没有读入,比如流已经被关闭,那么IOException将被抛出。一旦读入字节,之后碰到其它读取失败,将不会抛出异常,而是视为到达流的末尾。方法正常退出,并返回实际读取的字节数。

	
public int read(byte[] buf) throws IOException

等价于read(buf,0,buf.length).

	
public long skip(long count) throws IOException

在到流末端之前,忽略最多count个byte。返回实际忽略的字节数目。如果count是负数,没有字节被忽略。

	
public int available() throws IOException

返回未堵塞前能够读取的字节数。缺省的实现是返回0。

	
public void close() throws IOException

关闭输入流。这个方法应该被调用来释放和这个流关联的任何资源(比如文件句柄)。一旦一个流被关闭,在这个流上面的操作将会抛出异常。关闭一个以前关闭的流将没有任何效果。缺省的实现是什么也不做。

InputStream的实现只需要子类提供单字节读取read方法,因为其他read方法都要依赖这个。大多数流都为了提升性能重写其它方法。available和close的缺省实现通常为了某个特定的流被重写。

下面这段代码利用input stream来统计一个文件或者System.in中的所有字节:
	
import java.io.*;
class CountBytes{
public static void main(String[] args)
throws IOException
{
InputStream in;
if(args.length == 0)
in = System.in;
else
in = new FileInputStream(args[0]);
int total = 0;
while(in.read()!=-1)
total++;
System.out.println(total + "bytes");
}
}


这段程序从命令行中得到文件名。变量in代表input stream。如果没有提供文件名,它将用标准input stream:System.in。如果提供了一个文件名,将构建一个FileInputStream类型的对象,这是InputStream的子类。

while循环统计出这个文件中所有的字节数。最后结果将为答应出来。

你可能会调用availabe方法设置total, 但是这样对大多数流类都没有用。available方法返回在不被阻塞前能够读到的字节数。对于一个文件,可用的字节数通常就是它的整个内容。如果System.in是一个和键盘关联的流,答案可能会是0。当等待输入时,read方法就会阻塞。

20.2.2 OutputStream
抽象类OutputStream和InputStream很相似,它提供为向一个地方写字节提供一种抽象。它的方法是:


public abstract void write(int b) throws IOException

将b作为字节写入。传入的字节是int类型,因为参数可以是一个字节的运算结果。运算中的字节都是int类型,所以将参数定为int类型,这样就避免最后byte转型。注意,只是这个整数的低八位被写入。这个方法将被阻塞知道字节写入。


public void write(byte[] buf, int offset, int count)throws IOException

写入字节数组中的一部分,从buf[offset]开始写入count个字节。这个方法将被阻塞直到字节写入。


public void write(byte[] buf)throws IOException

等价于write(buf,0,buf.length)。


public void flush() throws IOException

冲洗流。如果这个流缓冲着来自write方法的字节,flush方法将直接将其写到目的地。如果目的地是另外一个流,这个流也会被冲洗。一个flush调用,会导致一串流的缓冲区被冲洗。如果这个流不是缓冲的,flush什么也不做,这也是默认实现。这个方法来自Flushable接口。


public void close() throws IOException

关闭输出流。这个方法应该被调用来释放与流关联的任何资源(比如文件句柄)。一旦流被关闭,之后在流上的操作将会导致IOException被抛出。关闭一个已经关闭的流,没有任何效果。close的缺省实现是什么也不做。

OutputStream的实现只需要其子类提供单字节write方法,因为其他的write方法的定义都依靠这个方法。大多数流为了提升性能都重写了这些方法。对于某些特殊的流,flush和close方法将被重写,比如缓冲流当关闭时应该被冲洗。

下面这段程序将把输入复制到输出,顺便转换一个特殊字节。TranslateByte接收两个参数:from和to。如果输入中有值和from相等,就转换为to。

import java.io.*;
class TranslateByte{
public static void main(String[] args)
throws IOException
{
byte from = (byte)args[0].charAt(0);
byte to = (byte)args[0].charAt(0);
int b;
while((b=System.in.read())!=-1)
System.out.write(b==from?to:b);
}
}


比如,如果你要这样调用这段程序:
java TranslateByte b B
然后输入abracadabra!, 我们将会得到:
aBracadaBra!

操作读入未写出的数据流,应该使用Filter流,而不是像这段代码。在20.5.2将介绍filter.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值