auto commit
This commit is contained in:
parent
cc52775429
commit
eace8369dd
123
notes/Java IO.md
123
notes/Java IO.md
@ -40,8 +40,7 @@ File 类可以用于表示文件和目录的信息,但是它不表示文件的
|
||||
递归地输出一个目录下所有文件:
|
||||
|
||||
```java
|
||||
public static void listAllFiles(File dir)
|
||||
{
|
||||
public static void listAllFiles(File dir) {
|
||||
if (dir == null || !dir.exists()) {
|
||||
return;
|
||||
}
|
||||
@ -60,8 +59,7 @@ public static void listAllFiles(File dir)
|
||||
使用字节流操作进行文件复制:
|
||||
|
||||
```java
|
||||
public static void copyFile(String src, String dist) throws IOException
|
||||
{
|
||||
public static void copyFile(String src, String dist) throws IOException {
|
||||
FileInputStream in = new FileInputStream(src);
|
||||
FileOutputStream out = new FileOutputStream(dist);
|
||||
byte[] buffer = new byte[20 * 1024];
|
||||
@ -78,7 +76,11 @@ public static void copyFile(String src, String dist) throws IOException
|
||||
|
||||
<div align="center"> <img src="../pics//DP-Decorator-java.io.png" width="500"/> </div><br>
|
||||
|
||||
Java I/O 使用了装饰者模式来实现。以 InputStream 为例,InputStream 是抽象组件,FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作。FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能,例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
|
||||
Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
|
||||
|
||||
- InputStream 是抽象组件;
|
||||
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
|
||||
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能,例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
|
||||
|
||||
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
|
||||
|
||||
@ -99,8 +101,7 @@ DataInputStream 装饰者提供了对更多数据类型进行输入的操作,
|
||||
逐行输出文本文件的内容:
|
||||
|
||||
```java
|
||||
public static void readFileContent(String filePath) throws IOException
|
||||
{
|
||||
public static void readFileContent(String filePath) throws IOException {
|
||||
FileReader fileReader = new FileReader(filePath);
|
||||
BufferedReader bufferedReader = new BufferedReader(fileReader);
|
||||
String line;
|
||||
@ -126,7 +127,7 @@ UTF-16be 中的 be 指的是 Big Endian,也就是大端。相应地也有 UTF-
|
||||
|
||||
Java 使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,而是说 char 这种类型使用 UTF-16be 进行编码。char 类型占 16 位,也就是两个字节,Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。
|
||||
|
||||
String 可以看成一个字符序列,可以指定一个编码方式将它转换为字节序列,也可以指定一个编码方式将一个字节序列转换为 String。
|
||||
String 可以看成一个字符序列,可以指定一个编码方式将它编码为字节序列,也可以指定一个编码方式将一个字节序列解码为 String。
|
||||
|
||||
```java
|
||||
String str1 = "中文";
|
||||
@ -151,8 +152,7 @@ byte[] bytes = str1.getBytes();
|
||||
序列化的类需要实现 Serializable 接口,它只是一个标准,没有任何方法需要实现,但是如果不去实现它的话而进行序列化,会抛出异常。
|
||||
|
||||
```java
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException
|
||||
{
|
||||
public static void main(String[] args) throws IOException, ClassNotFoundException {
|
||||
A a1 = new A(123, "abc");
|
||||
String objectFile = "file/a1";
|
||||
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(objectFile));
|
||||
@ -188,7 +188,7 @@ private static class A implements Serializable
|
||||
|
||||
transient 关键字可以使一些属性不会被序列化。
|
||||
|
||||
**ArrayList 序列化和反序列化的实现** :ArrayList 中存储数据的数组是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。
|
||||
ArrayList 中存储数据的数组是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。
|
||||
|
||||
```java
|
||||
private transient Object[] elementData;
|
||||
@ -205,7 +205,7 @@ Java 中的网络支持:
|
||||
|
||||
## InetAddress
|
||||
|
||||
没有公有构造函数,只能通过静态方法来创建实例。
|
||||
没有公有的构造函数,只能通过静态方法来创建实例。
|
||||
|
||||
```java
|
||||
InetAddress.getByName(String host);
|
||||
@ -217,19 +217,24 @@ InetAddress.getByAddress(byte[] address);
|
||||
可以直接从 URL 中读取字节流数据。
|
||||
|
||||
```java
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
URL url = new URL("http://www.baidu.com");
|
||||
// 字节流
|
||||
|
||||
/* 字节流 */
|
||||
InputStream is = url.openStream();
|
||||
// 字符流
|
||||
|
||||
/* 字符流 */
|
||||
InputStreamReader isr = new InputStreamReader(is, "utf-8");
|
||||
|
||||
/* 提供缓存功能 */
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line = br.readLine();
|
||||
while (line != null) {
|
||||
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
line = br.readLine();
|
||||
}
|
||||
|
||||
br.close();
|
||||
}
|
||||
```
|
||||
@ -253,7 +258,7 @@ public static void main(String[] args) throws IOException
|
||||
- [Java NIO 浅析](https://tech.meituan.com/nio.html)
|
||||
- [IBM: NIO 入门](https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html)
|
||||
|
||||
新的输入/输出 (NIO) 库是在 JDK 1.4 中引入的。NIO 弥补了原来的 I/O 的不足,提供了高速的、面向块的 I/O。
|
||||
新的输入/输出 (NIO) 库是在 JDK 1.4 中引入的,弥补了原来的 I/O 的不足,提供了高速的、面向块的 I/O。
|
||||
|
||||
## 流与块
|
||||
|
||||
@ -271,7 +276,7 @@ I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重
|
||||
|
||||
通道 Channel 是对原 I/O 包中的流的模拟,可以通过它读取和写入数据。
|
||||
|
||||
通道与流的不同之处在于,流只能在一个方向上移动,(一个流必须是 InputStream 或者 OutputStream 的子类),而通道是双向的,可以用于读、写或者同时用于读写。
|
||||
通道与流的不同之处在于,流只能在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类),而通道是双向的,可以用于读、写或者同时用于读写。
|
||||
|
||||
通道包括以下类型:
|
||||
|
||||
@ -329,21 +334,41 @@ I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重
|
||||
以下展示了使用 NIO 快速复制文件的实例:
|
||||
|
||||
```java
|
||||
public static void fastCopy(String src, String dist) throws IOException
|
||||
{
|
||||
FileInputStream fin = new FileInputStream(src); /* 获取源文件的输入字节流 */
|
||||
FileChannel fcin = fin.getChannel(); /* 获取输入字节流的文件通道 */
|
||||
FileOutputStream fout = new FileOutputStream(dist); /* 获取目标文件的输出字节流 */
|
||||
FileChannel fcout = fout.getChannel(); /* 获取输出字节流的通道 */
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(1024); /* 为缓冲区分配 1024 个字节 */
|
||||
public static void fastCopy(String src, String dist) throws IOException {
|
||||
|
||||
/* 获得源文件的输入字节流 */
|
||||
FileInputStream fin = new FileInputStream(src);
|
||||
|
||||
/* 获取输入字节流的文件通道 */
|
||||
FileChannel fcin = fin.getChannel();
|
||||
|
||||
/* 获取目标文件的输出字节流 */
|
||||
FileOutputStream fout = new FileOutputStream(dist);
|
||||
|
||||
/* 获取输出字节流的通道 */
|
||||
FileChannel fcout = fout.getChannel();
|
||||
|
||||
/* 为缓冲区分配 1024 个字节 */
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
|
||||
|
||||
while (true) {
|
||||
int r = fcin.read(buffer); /* 从输入通道中读取数据到缓冲区中 */
|
||||
if (r == -1) { /* read() 返回 -1 表示 EOF */
|
||||
|
||||
/* 从输入通道中读取数据到缓冲区中 */
|
||||
int r = fcin.read(buffer);
|
||||
|
||||
/* read() 返回 -1 表示 EOF */
|
||||
if (r == -1) {
|
||||
break;
|
||||
}
|
||||
buffer.flip(); /* 切换读写 */
|
||||
fcout.write(buffer); /* 把缓冲区的内容写入输出文件中 */
|
||||
buffer.clear(); /* 清空缓冲区 */
|
||||
|
||||
/* 切换读写 */
|
||||
buffer.flip();
|
||||
|
||||
/* 把缓冲区的内容写入输出文件中 */
|
||||
fcout.write(buffer);
|
||||
|
||||
/* 清空缓冲区 */
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -448,10 +473,10 @@ while (true) {
|
||||
## 套接字 NIO 实例
|
||||
|
||||
```java
|
||||
public class NIOServer
|
||||
{
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
public class NIOServer {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
Selector selector = Selector.open();
|
||||
|
||||
ServerSocketChannel ssChannel = ServerSocketChannel.open();
|
||||
@ -463,32 +488,45 @@ public class NIOServer
|
||||
serverSocket.bind(address);
|
||||
|
||||
while (true) {
|
||||
|
||||
selector.select();
|
||||
Set<SelectionKey> keys = selector.selectedKeys();
|
||||
Iterator<SelectionKey> keyIterator = keys.iterator();
|
||||
|
||||
while (keyIterator.hasNext()) {
|
||||
|
||||
SelectionKey key = keyIterator.next();
|
||||
|
||||
if (key.isAcceptable()) {
|
||||
|
||||
ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();
|
||||
|
||||
// 服务器会为每个新连接创建一个 SocketChannel
|
||||
SocketChannel sChannel = ssChannel1.accept();
|
||||
sChannel.configureBlocking(false);
|
||||
|
||||
// 这个新连接主要用于从客户端读取数据
|
||||
sChannel.register(selector, SelectionKey.OP_READ);
|
||||
|
||||
} else if (key.isReadable()) {
|
||||
|
||||
SocketChannel sChannel = (SocketChannel) key.channel();
|
||||
System.out.println(readDataFromSocketChannel(sChannel));
|
||||
sChannel.close();
|
||||
}
|
||||
|
||||
keyIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||
StringBuilder data = new StringBuilder();
|
||||
|
||||
while (true) {
|
||||
|
||||
buffer.clear();
|
||||
int n = sChannel.read(buffer);
|
||||
if (n == -1) {
|
||||
@ -509,10 +547,9 @@ public class NIOServer
|
||||
```
|
||||
|
||||
```java
|
||||
public class NIOClient
|
||||
{
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
public class NIOClient {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
Socket socket = new Socket("127.0.0.1", 8888);
|
||||
OutputStream out = socket.getOutputStream();
|
||||
String s = "hello world";
|
||||
@ -526,9 +563,9 @@ public class NIOClient
|
||||
|
||||
内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。
|
||||
|
||||
向内存映射文件写入可能是危险的,仅只是改变数组的单个元素这样的简单操作,就可能会直接修改磁盘上的文件。修改数据与将数据保存到磁盘是没有分开的。
|
||||
向内存映射文件写入可能是危险的,只是改变数组的单个元素这样的简单操作,就可能会直接修改磁盘上的文件。修改数据与将数据保存到磁盘是没有分开的。
|
||||
|
||||
下面代码行将文件的前 1024 个字节映射到内存中,map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,您可以像使用其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行映射。
|
||||
下面代码行将文件的前 1024 个字节映射到内存中,map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,可以像使用其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行映射。
|
||||
|
||||
```java
|
||||
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
|
||||
|
Loading…
x
Reference in New Issue
Block a user