IO 操作案例

Catalogue
  1. 1 IO
  2. 2 Socket
  3. 3 Okio
  4. 4 NIO
  5. 5 AIO

本文主要记录了 Java IO 相关的基本操作,涵盖传统IO、Socket、Okio、NIO、AIO,目的是为了以后再遇到 IO 操作相关的需求时,即便忘记该怎么写了,也能通过本文中对应的例子得到启发。对于本文没有涉及到的具有代表性的例子,以后遇到后再补充。

1 IO

1
2
3
4
5
6
7
8
9
10
private static void io1() {
try (OutputStream outputStream = new FileOutputStream(file)) {
outputStream.write('a');
outputStream.write('b');
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

往 file 文件写数据。

1
2
3
4
5
6
7
8
9
10
private static void io2() {
try (InputStream inputStream = new FileInputStream(file)) {
System.out.println((char) inputStream.read());
System.out.println((char) inputStream.read());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

从 file 文件中读数据。

1
2
3
4
5
6
7
8
9
10
11
12
private static void io3() {
try (InputStream inputStream = new FileInputStream(file);
Reader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader)
) {
System.out.println(bufferedReader.readLine());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

通过 buffer 中读数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static void io4() {
try (OutputStream outputStream = new FileOutputStream(file);
Writer writer = new OutputStreamWriter(outputStream);
BufferedWriter bufferedWriter = new BufferedWriter(writer)
) {
bufferedWriter.write('a');
bufferedWriter.write('b');
//当 Buffered 被关闭时会自动 flush,而 try(...) 写法自动包含了关闭 Buffered 的逻辑,所以可以省略 flush() 方法调用。
//bufferedWriter.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

往 buffer 中写数据,之后保存到文件。
注意: BufferedWriter 中的缓冲的数据量只有达到 8192 个字节才会被刷新一次数据(共 8192 个字节)到文件中,除非你主动调用它的 flush 方法,所以我们从 buffer 写数据到文件中时总是会调用它的 flush 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static void io5() {
try (InputStream inputStream = new FileInputStream(file);
OutputStream outputStream = new FileOutputStream(outFile)
) {
byte[] data = new byte[1024];
int read;
while ((read = inputStream.read(data)) != -1) {
outputStream.write(data, 0, read);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

将数据从 file 文件复制到 outFile 文件。

知识补充
File 文件操作可参考 这篇文章

2 Socket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static void socket1() {
try (ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))
) {
String data;
while (true) {
data = reader.readLine();//读取客户端数据
writer.write(data);
writer.write("\n");
writer.flush();//发送数据到客户端
}
} catch (IOException e) {
e.printStackTrace();
}
}

服务端代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
private static void socket2() {
try (Socket client = new Socket("serverName", 8080);
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer)
) {
out.writeUTF("Hello from client");
System.out.println("服务器响应: " + in.readUTF());
} catch (IOException e) {
e.printStackTrace();
}
}

客户端代码。

Socket 基础知识可参考 这篇文章

Socket 实际使用可参考笔者的 ITalk项目

3 Okio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static void okio1() {
try (Source source = Okio.source(file)) {
Buffer buffer = new Buffer();
source.read(buffer, 1024);
System.out.println(buffer.readUtf8Line());

//也可和传统 io 交互
//buffer.outputStream();
//buffer.inputStream();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

从 file 中读数据到 Buffer。

1
2
3
4
5
6
7
8
9
10
11
private static void okio2() {
try (Source source = Okio.source(file);
BufferedSource bufferedSource = Okio.buffer(source)
) {
System.out.println(bufferedSource.readUtf8());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

从 file 中读数据到 BufferedSource 。

4 NIO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static void nio1() {
try (RandomAccessFile file = new RandomAccessFile("text.txt", "r");
FileChannel channel = file.getChannel()
) {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
channel.read(byteBuffer);
byteBuffer.flip();
System.out.println(Charset.defaultCharset().decode(byteBuffer));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

从 text.txt 中读数据到 ByteBuffer 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private static void nio2() {
try {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(8080));
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
int n = selector.select();//这里是阻塞的。
if (n == 0) continue;
Iterator ite = selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
if (key.isAcceptable()) {
SocketChannel clntChan = ((ServerSocketChannel) key.channel()).accept();
clntChan.configureBlocking(false);
//将选择器注册到连接到的客户端信道,
//并指定该信道key值的属性为OP_READ,
//同时为该信道指定关联的附件
clntChan.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(1024));
}
if (key.isReadable()) {
// handleRead(key);
}
if (key.isWritable() && key.isValid()) {
// handleWrite(key);
}
if (key.isConnectable()) {
System.out.println("isConnectable = true");
}
ite.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

Selector 的使用。

参考链接>>

PS:参考链接中 “实现原理” 部分的内容没看懂,后面有时间再研究吧。

5 AIO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static void aio1() {
Path path = Paths.get("text.txt");
try (AsynchronousFileChannel fileChannel =
AsynchronousFileChannel.open(path, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;
Future<Integer> operation = fileChannel.read(buffer, position);
while (!operation.isDone()) ;
buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
System.out.println(new String(data));
buffer.clear();
} catch (IOException e) {
e.printStackTrace();
}
}

同步方式读取 text.txt 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static void aio2() {
Path path = Paths.get("text.txt");
try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate((int) fileChannel.size());
fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer byteBuffer) {
System.out.println("result = " + result);
byteBuffer.flip();
byte[] data = new byte[byteBuffer.limit()];
byteBuffer.get(data);
System.out.println(new String(data));
byteBuffer.clear();
}

@Override
public void failed(Throwable throwable, ByteBuffer attachment) {

}
});
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Sleeping for 5 seconds...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

异步方式读取 text.txt 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static void aio3() {
Path path = Paths.get("text.txt");
try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE)) {
String data = "test data";
ByteBuffer buffer = ByteBuffer.allocate(data.length());
buffer.put(data.getBytes());
buffer.flip();

long position = 0;
Future<Integer> operation = fileChannel.write(buffer, position);
buffer.clear();

while (!operation.isDone()) ;

System.out.println("Write done");
} catch (IOException e) {
e.printStackTrace();
}
}

同步方式往 text.txt 写数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static void aio4() {
Path path = Paths.get("text.txt");
try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;
buffer.put("test data".getBytes());
buffer.flip();

fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
System.out.println("bytes written: " + result);
}

@Override
public void failed(Throwable exc, ByteBuffer attachment) {
System.out.println("Write failed");
exc.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Sleeping for 5 seconds...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

异步方式往 text.txt 写数据。

AIO 参考链接>>