javaI/O流小结

【README】

1.本文总结java IO读取或写入数据的方式和相关类说明;

2.java IO建立在流之上的。输入流读取数据,输出流写入数据;

3.过滤器流-filter stream,可以串连(修饰)到输入流和输出流上;

4.补充:

  1. 补充1:java流操作数据的单位是字节
  2. 补充2:流是同步的。 当程序请求一个流读写一段数据时,在做操作前,它要等待读写的数据到达或可用;
  3. 补充3:javaIO的实现方式还包括通道和缓存区的非阻塞IO;

5.阅读器reader或书写器writer,可以串链到输入流和输出流上,操作数据的单位是字符


【1.1】java流

【1.1】java输入输出流基类(操作字节)

java基本输出流类是  OutputStream;写入字节;

java基本输入流类是 InputStream; 读取字节;


【1.2】过滤器流(操作字节,对字节加工或把字节转为字符)

1.过滤器基类是 FilterInputStream, FilterOutputStream;分别继承 InputStream, OuputStream;

2.过滤器分为2种:

  1. 过滤器流;过滤器流主要将原始数据作为字节处理;如压缩数据或解释为二进制数字;
  2. 阅读器和书写器;把不同编码格式的字节转为字符文本进行处理;

3.输入过滤器流 FilterInputStream 子类列表

public
class FilterInputStream extends InputStream {
   
   
  1. DataInputStream;二进制读写数据;
  2. GZIPInputStream;压缩;
  3. HttpInputStream;支持http连接;
  4. TelnetInputStream;只是telnet连接;模拟客户端登录服务器协议;
  5. ZipInputStream; 压缩;

4.输出过滤器流 FilterOuputStream 子类;  

public
class FilterOutputStream extends OutputStream {
   
   
  1. DataOutputStream;
  2. GZIPOutputStream;
  3. HttpSendOutputStream;
  4. TelnetOutputStream;
  5. ZipOutputStream;

5.多个过滤器流如何串链在一起处理字节流;


【1.2.1】多个过滤器链在一起

1.把 FileInputStream 和 BufferedInputStream 串链在一起 

@Test
    public void t1() throws Exception {
       FileInputStream fis = new FileInputStream("D:\\temp\\hello5.txt");
       BufferedInputStream bis = new BufferedInputStream(fis);
    }

【1.3】缓冲流(操作字节,缓冲)

1.分为输入缓冲流 BufferedInputStream, 输出缓冲流 BufferedOutputStream ;

2.缓冲流的作用

  • 2.1 对于输入缓冲流而言, 一次性不是读取一个字节,而是读取多个字节如1k个字节,减少磁盘io,提高读取性能;
  • 2.2 对于输出缓冲流而言,一次性不是写入一个字节,而是写入多个字节如1k;特别对于网络连接,一次发送一个字节,每次报文头开销40字节,即每发送1个字节就会附加40个字节报文头,性能非常低下;若一次写入多个字节,则报文头开销占比会小很多,传输效率大大增加;

【1.4】PringStream(操作字节,丢弃)

PrintStream 是有害的;应该避开它;

  • 问题1,因为 println() 的输出与平台有关;
  • 问题2,PrintStream假定使用所在平台的默认编码方式;
  • 问题3,printStream 吞掉所有异常;

【1.5】数据流(操作字节,二进制格式)

1.数据流基本类, DataInputStream, DataOutputStream ; 可以用二进制格式读写java基本数据类型和字符串;

try(DataOutputStream dataOutputStream = new DataOutputStream(
            new BufferedOutputStream(new FileOutputStream("D:\\temp\\hello2.txt")))) {
            dataOutputStream.write("hellworld2.这里是中国".getBytes(StandardCharsets.UTF_8));
     }

【2】阅读器和书写器(操作字符)

1.阅读器和书写器, 操作数据的单位是字符而不是字节;

2.基类分别为 Reader, Writer ;

3.它们最重要的子类是 InputStreamReader 和 OutputStreamWriter类(依赖底层输入输出流);分别把字节转为字符进行读取,把字符转为字节进行写入; 可以在创建实例时指定字符编码方式,不用每次处理的时候都去指定编码方式

4.其他原始阅读器和书写器(不依赖底层输入输出流)

  1. FileReader
  2. FileWriter
  3. StringReader
  4. StringWriter
  5. CharArrayReader
  6. CharArrayWriter
// 书写器 
try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
    new BufferedOutputStream(new FileOutputStream("D:\\temp\\hello4.txt")), StandardCharsets.UTF_8)) {
        outputStreamWriter.write("helloworld4.这里是中国");
}

// 阅读器
try (InputStreamReader inputStreamReader = new InputStreamReader(
    new FileInputStream("D:\\temp\\hello4.txt"), StandardCharsets.UTF_8)) {
        StringBuilder stringBuilder = new StringBuilder();
        int c = 0;
        while((c = inputStreamReader.read()) != -1) {
            stringBuilder.append((char)c);
        }
        System.out.println();
        System.out.println(stringBuilder.toString());
}

【2.1】过滤器阅读器和书写器

1,过滤器阅读器和书写器列表

  1. BufferedReader;缓冲读取器;
  2. BuffererWriter; 缓冲写入器;
  3. LineNumberReader;
  4. PushbackReader;
  5. PrintWriter;(用于替换PrintStream,但也存在小问题)

2,BufferedReader

有1个readLine(),可以读取一行字符,并作为字符串返回; 

try(BufferedReader bufferedReader = new BufferedReader(
    new InputStreamReader(new FileInputStream("D:\\temp\\hello4.txt"), StandardCharsets.UTF_8))) {
        String result = bufferedReader.readLine();
        System.out.println(result);
}

【3】流关闭方式

1. 方式1, 通过 try-finally 块关闭; 把关闭流代码放在 finally 里面;

2.方式2,java7引入了 带资源的try构造方式,可以更简洁地完成流关闭;如下:

 try(DataOutputStream dataOutputStream = new DataOutputStream(
                new BufferedOutputStream(new FileOutputStream("D:\\temp\\hello2.txt")))) {
            dataOutputStream.write("hellworld2.这里是中国".getBytes(StandardCharsets.UTF_8));
        }

【3.1】如何优雅关闭流

1. 之所以使用带资源的try的构造方式新建的流可以自动关闭,其原因在于, 流实现了 AutoCloseable 接口, 如下:以 DataOutputStream 为例;

public
class DataOutputStream extends FilterOutputStream implements DataOutput {
...

public
class FilterOutputStream extends OutputStream {
...

public abstract class OutputStream implements Closeable, Flushable {
...

public interface Closeable extends AutoCloseable {
...

public interface AutoCloseable {
    void close() throws Exception;
}

2. close方法如下实现的? 参见 FilterOutputStream.close() 方法 ;  所以它在关闭流的时候,会先刷新缓冲到底层流;

 public void close() throws IOException {
        try (OutputStream ostream = out) { // 这里其实也是一个 try资源块 
            flush();
        }
    }

public void flush() throws IOException {
        out.flush();
    }

3.我们再看下 AutoCloseable 的类说明如下:

一个可能持有资源(例如文件或套接字句柄)直到关闭的对象。 AutoCloseable 对象的 close() 方法在退出 try-with-resources 块时自动调用,该块已在资源规范标头中声明了该对象。 这种构造确保及时释放,避免资源耗尽异常和否则可能发生的错误。
API注意事项:

即使不是所有的子类或实例都拥有可释放的资源,基类也有可能实现 AutoCloseable,而且实际上很常见。

对于必须完全通用的代码,或者当知道 AutoCloseable 实例需要资源释放时,建议使用 try-with-resources 构造。 但是,当使用 java.util.stream.Stream 等支持基于 I/O 和非基于 I/O 的形式时,使用非 I/O 时通常不需要 try-with-resources 块 - 基于形式。


【4】java IO流小结

【4.1】输入输出字节流类结构

【4.1.1】常用输入字节流类结构-InputStream

 【4.1.2】常用输出字节流类结构-OutputStream


 【4.2】输入输出字符流类结构

【4.2.1】常用输入字符流类结构-Reader

 【4.2.2】常用输出字符流类结构-Writer

猜你喜欢

转载自blog.csdn.net/PacosonSWJTU/article/details/121061263