Java网络编程学习笔记(2)——Java的I/O

Java的I/O建立于流之上,输入流,输出流,过滤流(Filter)可以串联到输入流输出流上

输出流OutputStream

这里写图片描述
用法:

//声明OutputStream输入流对象
OutputStream out;
//out.write(int b)方法,只能读取一个byte(0-255),b的取值超过的话,会只默认读取最低字节。
out.write(b);

一般一次写入1字节效率不高,例如流出以太网卡的每个TCP分片包含至少40字节的开销用于路由与纠错,而且如果增加网络层协议的开销,情况可能更糟糕。因此大多数TCP/IP实现都会在某种程度上缓存数据,也就是说它们在内存上积累字节,只有积累到一定量,或者积累了一定时间后,才将所积累数据发送到目的。
更快的用法:

out.write(byte[] data);
out.write(byte[] data, int offset, int length);

刷新(flush)输出流:
例如,假如已经向使用HTTP Keep-Alive的HTTP 1.1服务器写入300字节的请求,通常你会等待响应,然后再发送更多的数据。不过如果输出流有一个1024字节的缓冲区,那么这个流在发送缓冲区的数据之前会等待更多的数据到达,在服务器响应到达前不会写入更多的数据,但是响应永远也不会到来,因为请求还没有发送,flush()方法可以强迫缓冲流发送数据。

当结束一个流操作时,通过调用close()方法将其关闭,会释放与这个流关联的所有资源。
一个长时间运行的程序,如果未能关闭一个流,则会泄露文件句柄,网络端口和其他资源。
推荐模式:
这里写图片描述

输入流InputStream

InputStream基本方法:

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

read()方法只读取一字节,但它会返回int,这样把结果存到字节数组之前,就必须进行类型转换。

input[i] = (byte) b;

但是,一般尝试读取可能不能完全读到,考虑到这一点,读取多字节的方法会返回实际的读取数。
它尝试从InputStream in 向数组input中读入1024字节,不过如果只有512字节可用。

byte[] input = new byte[1024];
int bytesRead = in.read(input);

为保证你希望的数据都能真正读取到,要把读取的方法放在循环中,这样会重复读取,直到数组填满为止。

int bytesRead = 0;
int bytesToRead = 1024;
byte[] input = new input[bytesToRead];
while(bytesRead < bytesToRead){
    bytesRead += in.read(input, bytesRead, bytesToRead - bytesRead);
}

所有三个read()的方法都用返回-1表示流的结束。
所以对于上面的循环读取,改进办法:

int bytesRead = 0;
int bytesToRead = 1024;
byte[] input = new input[bytesToRead];
while(bytesRead < bytesToRead){
    int result= in.read(input, bytesRead, bytesToRead - bytesRead);
    if(result == -1)break;
    bytesRead += result;
}

这里写图片描述
两个方法:

public void mark(int readAheadLimit)
public void reset() throws IOException

mark()方法标记流的当前位置,在以后某个时刻,可以用reset()方法把流重置之前标记的位置,接下来的读取操作会返回从标记位置开始的数据。不过不能随心所欲的向前重置任意远的位置,从标记处读取和重置的字节数由mark()的readAheadLimit参数确定。

过滤器流

这里写图片描述
每个过滤器输出流,都有与OutputStream,InputStream相同的write(), close(), flush(), read(), available()方法。
这里写图片描述
这种连接是永久的,过滤器无法与流断开连接。

缓冲流

构造函数:
这里写图片描述
BufferedInputStream没有声明自己的任何新方法,只是覆盖了InputStream的方法,他支持标记和重置,BufferedOutputStream也没有声明自己的任何新方法,区别在于每次写入会把数据放在缓存区,而不是直接放在底层的输出流,因此需要发送数据时,应当刷新输出流这一点非常重要。

PrintStream

过滤器输出流,System.out就是一个过滤器输出流,不过还可以使用 下面两个构造函数将其他输出流串连到打印流:

public PrintStream(OutputStresm out)
public PrintStream(OutputStream out, boolean autoFlush)

这里写图片描述
(PrintStream本身还是很有害的,不要使用!!)

数据流

可以用二进制格式读写Java基本数据类型和字符串,所用的二进制格式主要用于在两个不同的Java程序之间交换数据(可能通过网络连接,数据文件,管道或者其他中间介质),输出流写入什么数据,输入流就能读取什么数据。
这碰巧与大多数交换二进制数的Internet协议所用的格式相同。
这里写图片描述
这里写图片描述
这里写图片描述

阅读器和书写器

(主要用于字节与特定编码字符之间相转换,输入输出流的镜像,功能更强大)
这里写图片描述
Java.io.Reader, Java.io.Writer的具体子类有:

InputStreamReader
OutputStreamWriter
FileReader
FileWriter
StringReader
StringWriter
CharArrayReader
CharArrayWriter

这里写图片描述
用法示例:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

PrintWriter

推荐使用来替换PrintStream(System.out),PrintWriter.println()用法完全覆盖System.out.println()
这里写图片描述

(Java.io)总结:

输入流(InputStream),输出流(OutputStream)(基于字节)
文件输入流(FileInputStream),文件输出流(FileOutputStream)
缓冲流(BufferedInputStream,BufferedOutputStream)(具有缓冲效果,属于过滤器输入输出流)
过滤器输出流(PrintStream,包括System.out)(用于打印)
数据流(DataInputStream,DataOutputStream)(直接传输数据类型)
阅读器书写器(Reader, Writer两个父类,上面IOStream的镜像,更推荐使用)
输入阅读器,输出书写器 (InputStreamReader, OutputStreamWriter)(直接基于字符,而不是字节)
文件阅读器,文件书写器(FileReader, FileWriter)
字符串,字符,阅读,书写器(StringReader,StringWriter,CharArrayReader,CharArrayWriter)
缓冲阅读器,缓冲书写器(BufferedReader,BufferedWriter)
过滤器书写器(PrintWriter)

猜你喜欢

转载自blog.csdn.net/qq_37423198/article/details/79612955