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