1. Java的IO操作分为三大类
– 基于字节流的操作
• 底层操作,因为不关注信息的分段,只能对字节进行处理,往往不适用于高级操作
– 基于字符流的操作
• 高级操作,基于字符,可划分信息段
– 基于NIO的操作
• 非阻塞式操作,性能最好
– 基于字节流的操作
• 底层操作,因为不关注信息的分段,只能对字节进行处理,往往不适用于高级操作
– 基于字符流的操作
• 高级操作,基于字符,可划分信息段
– 基于NIO的操作
• 非阻塞式操作,性能最好
2. 字节流
– 所有基于字节流的类都派生自InputStream或者OutputStream
– 所有基于字节流的类都派生自InputStream或者OutputStream
– 及时关闭流
– 注意字节流是低层次的处理,必要时使用字符流
– 注意字节流是低层次的处理,必要时使用字符流
import java.io.*;
public class CopyBytes {
public static void main(String[] args) throws IOException {
FileInputStream in = null;
public class CopyBytes {
public static void main(String[] args) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("xanadu.txt");
out = new FileOutputStream("outagain.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
}
不关闭,会造成资源泄漏,文件句柄之类的
3. 字符流
– 所有字符流派生自Reader或者Writer
– 基于行的操作
– 所有字符流派生自Reader或者Writer
– 基于行的操作
4. 缓存流
– 缓存流可以避免不断的对磁盘进行读写操作,提高性能
– 记得flush缓存流(确保缓存的内容写入)
– 有四种缓存流:
• BufferedInputStream/BufferedOutputStream
• BufferedReader/BufferedWriter
– 分别对应的是处理字节和字符的流,使用中需要注意
– 缓存流可以避免不断的对磁盘进行读写操作,提高性能
– 记得flush缓存流(确保缓存的内容写入)
– 有四种缓存流:
• BufferedInputStream/BufferedOutputStream
• BufferedReader/BufferedWriter
– 分别对应的是处理字节和字符的流,使用中需要注意
5. 数据流
– 数据流可以根据数据的类型进行操作
• 包括从boolean到double的所有基本类型
• 不能处理对象类型
• 数据流实现DataInput和DataOutput接口
– 例子:
– 数据流可以根据数据的类型进行操作
• 包括从boolean到double的所有基本类型
• 不能处理对象类型
• 数据流实现DataInput和DataOutput接口
– 例子:
in = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile)));
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));
for (int i = 0; i < prices.length; i ++) {
out.writeDouble(prices[i]);
out.writeInt(units[i]);
out.writeUTF(descs[i]);
}
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));
for (int i = 0; i < prices.length; i ++) {
out.writeDouble(prices[i]);
out.writeInt(units[i]);
out.writeUTF(descs[i]);
}
6. 文件操作
– java.nio.file.Path是文件操作的主要支持类
• 可创建路径对象——Paths.get
• 获取路径信息——查看Path相关API文档
• 删除路径中的冗余信息,如.和..
• 合并路径——Path.resolve
– 流基本都是实现了Closable接口的,注意在使用完毕之后调用close方法,否则会出现资源
泄露
– 有些文件操作在某些操作系统中是原子操作,因此需要注意在多进程或多线程下的文件操作
– java.nio.file.Path是文件操作的主要支持类
• 可创建路径对象——Paths.get
• 获取路径信息——查看Path相关API文档
• 删除路径中的冗余信息,如.和..
• 合并路径——Path.resolve
– 流基本都是实现了Closable接口的,注意在使用完毕之后调用close方法,否则会出现资源
泄露
– 有些文件操作在某些操作系统中是原子操作,因此需要注意在多进程或多线程下的文件操作
查看文件属性(Files)
– Exists、 notExists、 isReadable、 isWritable、 isExecutable
删除文件或目录(Files)
– Delete、 deleteIfExists
拷贝文件(Files)
– copy
移动文件或目录
– move
– Exists、 notExists、 isReadable、 isWritable、 isExecutable
删除文件或目录(Files)
– Delete、 deleteIfExists
拷贝文件(Files)
– copy
移动文件或目录
– move
try() 写法,自动关闭()内资源
为什么使用NIO
– 面向块的操作,而不是流的操作
什么是缓冲区
– Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。 在 NIO 中加入 Buffer 对象,体
现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接
读到 Stream 对象中。
– 在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在
写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区
中。
– 缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一
个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/
写进程。
– 面向块的操作,而不是流的操作
什么是缓冲区
– Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。 在 NIO 中加入 Buffer 对象,体
现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接
读到 Stream 对象中。
– 在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在
写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区
中。
– 缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一
个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/
写进程。
try (SeekableByteChannel sbc = Files.newByteChannel(file)) {
ByteBuffer buf = ByteBuffer.allocate(10);
String encoding = System.getProperty("file.encoding");
while (sbc.read(buf) > 0) {
buf.rewind();
System.out.print(Charset.forName(encoding).decode(buf));
buf.flip();
}
} catch (IOException x) {
System.out.println("caught exception: " + x);
}
什么是channel
– Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就
像是流。
– 正如前面提到的,所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,
相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节
,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
通道类型
– 通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是
InputStream 或者 OutputStream 的子类), 而 通道 可以用于读、写或者同时用于读写。
– 因为它们是双向的,所以通道可以比流更好地反映底层操作系统的真实情况。特别是在 UNIX
模型中,底层操作系统通道是双向的。
ByteBuffer buf = ByteBuffer.allocate(10);
String encoding = System.getProperty("file.encoding");
while (sbc.read(buf) > 0) {
buf.rewind();
System.out.print(Charset.forName(encoding).decode(buf));
buf.flip();
}
} catch (IOException x) {
System.out.println("caught exception: " + x);
}
什么是channel
– Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就
像是流。
– 正如前面提到的,所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,
相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节
,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
通道类型
– 通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是
InputStream 或者 OutputStream 的子类), 而 通道 可以用于读、写或者同时用于读写。
– 因为它们是双向的,所以通道可以比流更好地反映底层操作系统的真实情况。特别是在 UNIX
模型中,底层操作系统通道是双向的。
VisualVM 监控器