Java网络编程(过滤器流)

InputStream

OutputStream

是相当原始的类。它们可以单个或成组地读/写字节,但仅此而已。要确定这些字节的含义,这完全要依靠程序员自己。不过,有一些极为常见的数据格式,如果在类库中提供这些数据格式的固定实现,会很有好处。例如,许多作为网络协议一部分传递的整数是32位big-endian整数。许多通过Web发送的文本是7位ASCII、8位Latin-1或多字节UTF-8。许多由FTP传输的文件存储为zip格式。Java提供了很多过滤器类,可以附加到原始类中,在原始字节和各种格式之间来回转换。

过滤器

有两个版本:过滤器流以及阅读器和书写器。

过滤器流仍然主要将原始数据作为字节处理,通过压缩数据或解释为二进制数字。阅读器和书写器处理各种编码文本的特殊情况,如UTF-8和ISO 8859-1。

过滤器流以链的形式进行组织。链中的每个环节都接收前一个过滤器或流的数据,并把数据传递给链中的下一个环节。在这个示例中,从本地网络接口接收到一个加密的文本文件,在这里本地代码将这个文件表示为TelnetInputStream。通过一个BufferedInputtStream缓冲这个数据来加速整个过程。由一个CipherInputStream将数据解密。再由一个GZIPInputStream解压解密后的数据。一个InputStream将解压后的数据转换为Unicode文本。最后,文本由应用程序进行处理。

扫描二维码关注公众号,回复: 3441346 查看本文章

每个过滤器输出流都有与java.io.OutputStream相同的write()、close()和flush()方法。

每个过滤器输入流都有与java.io.InputStream相同的read()、close()、available()方法。

在有些情况下,如BufferedInputStream和BUfferedOutputStream,过滤器可能只有这些方法。过滤纯粹是内部操作,不提供任何新的公共接口。不过,在大多数情况下,过滤器流会增加一些公共方法提供额外的作用。有时除了平常的read()和write()方法外,还需要使用这些方法,如PushbackInputStreamd的unread()方法。另外一些情况下,它们几乎完全代替了最初的接口。例如,PrintStream的write()方法就很少使用,而使用它的print()方法和printl()方法。

将过滤器串链到一起

过滤器通过其构造函数与流连接。例如下面的代码段将缓存文件data.txt的输入。首先,创建一个FileInputStream对象fin,为此将文件名作为参数传递给FileInputStream构造函数。然后通过将fin作为参数传递给BufferedInputStream构造函数来创建一个BufferedINputStream对象bin:


 

FileInputStream fin = new FileInputStream("data.txt");


BUfferedInputStream bin = new BufferedInputStream(fin);

在此之后,从文件data.txt读取文件可能会同时使用fin和bin的read()方法。不过,如果混合调用连接到同一个源的不同不同流,这可能会违反过滤器流的一些隐含的约定。大多数情况下,应当只使用链中最后一个过滤器进行实际的读/写。要想在编写代码时候尽量不带入这些bug,可以有意地重写底层输入流的引用。例如:

InputStream in = new FileInputStream("data.txt");


in = new BufferedInputStream(in);

执行这两行代码后,再没有任何方法能访问底层的文件输入流了,所以就不会不小心读取这个流破坏缓冲区。这个示 例之所以可行是因为BufferedInputStream可以多态的作为InputStream的实例,所以没必要区分InputStream和BufferedInputStream的方法 。如果使用超类中没有声明的过滤器流的其他方法,可以直接在一个流中构建另一个流。例如:

DataOutputSteam dout = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.txt")));

虽然这些语句有些长,不过很容易将这条语句分成多行,像这样:

DataOutputStream dout = new DataOutputStream(

                                            new BufferedOutputStream(

                                            new FileOutputStream("data.xt")

)

);

这种连接是永久的。过滤器无法与流断开。

缓冲流

BufferedOutputStream类将写入的数据存储到缓冲区(一个名为 buf的保护字节数组字段),直到缓冲区满或者刷新输出流。然后它将数据一次全部写入底层输出流。如果一次写入多字节,这与多次写入少量字节相比,前者往往要快的多。对于网络连接尤其这样,因为每个TCP片或UDP包都有一定的数量的开销,一般大约为40个字节。这意味着,如果一次发送1字节,那么发送1k数据实际上需要通过线缆发送40k,而一次全部发送只需要发送1k多一点点数据,大多数网卡和TCP实现自身都会提供一定程度的缓冲,所以实际的数量不会那么夸张。尽管如此,缓存网络输出经常会带来性能上的提升。

 BufferedINputStream类也有一个作为缓冲区的保护字节数组,名为buf。当调用某个流的read()方法时,它首先尝试从缓冲区获取请求的数据。只有当缓冲区没有数据时流才会从底层数据源中读取数据。

这时,它会从源中读取尽量多的数据存入缓冲区,而不管是否马上需要这些数据。不会立刻用到的数据可以在以后调用read()方法读取。当从本地磁盘读取文件的时候,从底层流读取几百字节的数据和读取1字节的数据几乎一样快。因此,缓冲可以显著提升性能。对于网络连接,这种效果不甚明显,在这里 瓶颈往往是网络传输速度,尽管如此,缓冲流输入没有什么坏处,随着网络速度的加快会变得更加的重要。

BufferedInputStream有两个构造函数,BufferedOutputStream也一样:


 

public BufferedInputStream (InputStream in);


public BufferedInputStream (InputStream in, int bufferSize);


public BufferedOutputStream (OutputStream out);


public BufferedOutputStream (OutputStream out, int bufferSize);

BufferedInputStream没有声明自己的任何新方法。它只覆盖了InputStream的方法。它支持标记和重置。两个多字节read()方法尝试根据需要多次从底层输入流读取数据,从而完全填充指定的数组或子数组。只有当数组或子数组完全填满之后,到达流的末尾或底层流阻塞而无法进行下一步读取时这两个read()才会返回。大多数输入流都不会这么做。它们在返回前只从底层流或数据源中读取一次。

BufferedOutputStream也没有声明自己的任何方法。调用它的方法和调用任何输出流的方法一样。区别在于每次写入会把数据放到缓冲区里面,而不是直接放到底层的输出流。因此,需要发送数据的时候应当刷新输出流。

PrintStream

PrintStream类是大多数程序员都会遇见的第一个过滤器输出流,因为System.out就是一个PrintStream。不过还可以使用下面两个构造函数将其他输出流串链到打印流:

public PrintStream(OutputStream out);


public PrintStream(OutputStream out, boolean autoFlush);

默认情况下,打印流应当显式的刷新输出。不过,如果autoFlush设置为true的话,那么每次写入1字节数组或换行,或者调用println()方法都会刷新输出流。

除了平常的write(),flush(),和clos()方法,PrintStream还有9个重载的print()方法和10个重载的println()方法。

public void print(boolean b)



public void print(char c)



public void print(int i)



public void print(long l)



public void print(double d)



public void print(char[] text)



public void print(String s)



public void print(Object o)



public void println()



public void println(boolean b)



public void println(char c)



public void println(int i)



public void println(long l)



public void println(float f)



public void println(double b)



public void println(char[] text)



public void println(String s)



public void println(Object o)

数据流

DataInputStream和DataOutputStream类提供了一些方法,可以用二进制 格式读/写Java的基本数据类型和字符串。所用的二进制格式主要用于在两个不同的Java程序之间交换数据。输出流写入什么数据,输入流就能读取什么数据。

DataOutputStream类提供了下面11种方法可以写入特定的Java数据类型:


 

public final void writeBoolean(boolean b) throws IOException


public final void writeByte(int b) throws IOException


public final void writeShort(int s) throws IOException


public final void writeChar(int c) throws IOException


public final void writeInt(int i) throws IOException


public final void writeLong(long l) throws IOException


public final void writeFloat(float f) throws IOException


public final void writeDouble(double b) throws IOException


public final void writeChars(String s) throws IOException


public final void writeBytes(String s) throws IOException


public final void writeUTF(String s) throws IOException


有9个读取二进制数据的方法,这些方法对应DataOutputStream的11个方法(writeBytes()和writeChars()没有对应方法)。


public final boolean readBoolean() throws IOException


public final byte readByte() throws IOException


public final char readChar() throws IOException


public final short readShort() throws IOException


public final int readInt() throws IOException


public final long readLong() throws IOException


public final float readFloat() throws IOException


public final double readDouble() throws IOException


public final String readUTF() throws IOException

猜你喜欢

转载自blog.csdn.net/young_1004/article/details/82925028
今日推荐