Java I/O学习

I/O应该是最核心的模块之一,刚开始接触时很容易被一层套一层的操作搞晕,所以需要对Java的I/O和NIO有个全局观,这样理解起来就容易多了。

I/O库概述

处理I/O的经典方式

数据流是Java与磁盘,数据库,网络等源或目的媒介数据通信的描述,可分为(面向人的)字符流/Character和(面向机器的)字节流/Byte.

缓冲流避免一个一个字符的读写,更加高效,常用来包装文件读写流.

  • 文件: File类表示文件,也表示目录
  • 字节流: InputStream/OutputStream: 及子类提供低层的字节流
  • 字符流: Writer/Reader: 处理的是字符流

旧风格中有些功能偶尔也有用。例如,处理文本文件时,FilterInputStream 类往往非常有用。

对于想使用类似于经典“管道”I/O 方式通信的线程来说,可使用PipedInputStream 和PipedReader类,以及对应的写入器。

常用类如下:

  • Streams/字节流:InputStream /OutputStream
    • 面向8位字节,二进制或和机器打交道的数据
    • FileInputStream/FileOutputStream:从文件读取字节,将字节写入文件
    • ByteArrayInputStream/ByteArrayOutputStream:从内存型的数组读取字节,将字节写入内存中的数组
  • 字符流: Reader/Writer
    • 面向字符(16位unicode),文本或人可读数据
    • Reader 喜欢从字节流读取字节并转换为字符. Writer 喜欢将字符转换为字节,以便将它们放在字节流上.
    • StringReader/StringWriter:在内存的 String 中读取和写入字符.
    • InputStreamReader/InputStreamWriter和子类 FileReader/FileWriter:充当字节流和字符流之间的桥梁.
  • 缓存流: 读大文件或频繁读有更高的性能
    • BufferedReader / BufferedWriter:在读取或写入另一个流时缓冲数据,使读写操作更高效.

处理I/O的现代方式

Java7 引入全新I/O API(NIO.2),在java.nio.file

  • Path接口: 表示文件的位置,内容有无均可
  • Files静态方法

常用类及方法:

  • Files
    • readAllBytes
    • readAllLines
    • write(Path,,StandardOpenOption.CREATE)
    • newInputStream/newOutputStream
    • find/walk: 递归遍历目录
  • Paths 和Path
    • Paths.get
    • getName
    • getParent
    • deleteIfExists
  • File
    • toPath: Path对象和File对象之间可以轻易的相互转换

NIO中的通道和缓冲区

缓冲区是对高性能I/O 的一种低层抽象,为指定基本类型组成的线性序列提供容器。

  • ByteBuffer: 字节序列,注重性能是替代byte[]数组
    • 支持直接缓冲区allocateDirect()
    • 或打包字节数组warp()
    • 由于是低层访问,需要处理字节顺序和整数基本类型的符号
    • 缓冲区这种抽象只存在于内存中
  • Channel: 用于和文件或网络操作(只读或只写)
    • 从通道中读取数据时会把字节存入缓冲区
    • 把数据写入通道时会从缓冲区中读取字节
  • FileChannel创建映射字节缓冲区

异步I/O

  • AsynchronousFileChannel
  • AsynchronousSocketChannel
  • AsynchronousServerSocketChannel

和异步通道交互有两种不同的方式:

  • 使用Future接口的方式
    • Futrue接口表示进行中的任务,可能已经完成,也可能还未完成。
    • idDone()和get()
  • 回调方式
    • 回调方式基于CompletionHandler 接口实现
    • completed()和failed()

处理异步I/O 时,如果想立即收到事件提醒,可以使用这种方式。例如,有大量I/O 操作要执行,但其中某次操作失败不会导致重大错误,这种情况就可以使用回调方式.

监视目录或访问目录

流操作

字符集

字符集名字大小写不敏感,中文和日文是可变字节编码

行操作

  • reader.readLine(): 只支持字符
  • Scanner: 功能更强,Scanner以文本格式读,PrintWriter以文本格式写
  • PrinterWriter: 支持多种类型或格式定义printf
  • System.out是一个PrintStream对象

注: 流操作要记得关闭资源,通常是外层的Buffer对象,避免占用文件句柄不释放。推荐使用try-with-resources(){}

二进制数据处理

// 复制二进制数据:
System.arraycopy()
Arrays.copyOfRange(buf, i, buf.length)

异常

  • IOException
    • EOFException
    • FileNotFoundException

扩展阅读