java 中文件NIO

1. 内存映射文件

通俗点,就是ReadFile和WriteFile这样的I/O系统函数, 在文件里来回地读、写、移动文件指针效率低 速度慢;CreateFileMapping函数允许应用程序把文件映射到一个进程,这样文件内的数据就可以用内存读/写指令来访问,提高效率。

再通俗点,就是比如 要读取一个文件里的东西 这时候你就得去硬盘读,但是映射到内存后 就可以直接对这块内存操作了;写操作也一个意思。。。。。就是把要在硬盘上搞的东西 弄到内存搞 搞起来方便

JDK1.4版本引入了java.nio包,对文件流进行读写操作,提供无阻塞模式,同时也提供了一种高效率的文件读写模式,内存映射文件,把文件某个区域块映射到内存,进行高效率的读写,主要用到下面类
java.nio.MappedByteBuffer;
java.nio.channels.FileChannel

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package com.bjmashibing.system.io;

import org.junit.Test;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class OSFileIO {

static byte[] data = "123456789\n".getBytes();
static String path = "/root/testfileio/out.txt";

//最基本的file写

public static void testBasicFileIO() throws Exception {
File file = new File(path);
FileOutputStream out = new FileOutputStream(file);
while(true){
Thread.sleep(10);
out.write(data);

}

}

//测试buffer文件IO
// 在jvm上开启 8kB 的数据空间 写满8字节之后调用系统syscall以8字节的新式写到pageCahe write(8KBbyte[])

public static void testBufferedFileIO() throws Exception {
File file = new File(path);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
while(true){
Thread.sleep(10);
out.write(data);
}
}



//测试文件NIO


public static void testRandomAccessFileWrite() throws Exception {


RandomAccessFile raf = new RandomAccessFile(path, "rw");

raf.write("hello mashibing\n".getBytes());
raf.write("hello seanzhou\n".getBytes());
System.out.println("write------------");
System.in.read();

raf.seek(4);
raf.write("ooxx".getBytes());

System.out.println("seek---------");
System.in.read();

FileChannel rafchannel = raf.getChannel();
//mmap 堆外 和文件映射的 byte not objtect
MappedByteBuffer map = rafchannel.map(FileChannel.MapMode.READ_WRITE, 0, 4096);


map.put("@@@".getBytes()); //不是系统调用 但是数据会到达 内核的pagecache
//曾经我们是需要out.write() 这样的系统调用,才能让程序的data 进入内核的pagecache
//曾经必须有用户态内核态切换
//mmap的内存映射,依然是内核的pagecache体系所约束的!!!
//换言之,丢数据
//你可以去github上找一些 其他C程序员写的jni扩展库,使用linux内核的Direct IO
//直接IO是忽略linux的pagecache
//是把pagecache 交给了程序自己开辟一个字节数组当作pagecache,动用代码逻辑来维护一致性/dirty。。。一系列复杂问题

System.out.println("map--put--------");
System.in.read();

// map.force(); // flush



raf.seek(0);

ByteBuffer buffer = ByteBuffer.allocate(8192);
// ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

int read = rafchannel.read(buffer); //buffer.put()
System.out.println(buffer);
buffer.flip();
System.out.println(buffer);

for (int i = 0; i < buffer.limit(); i++) {
Thread.sleep(200);
System.out.print(((char)buffer.get(i)));
}


}


@Test
public void whatByteBuffer(){

// ByteBuffer buffer = ByteBuffer.allocate(1024);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);


System.out.println("postition: " + buffer.position());
System.out.println("limit: " + buffer.limit());
System.out.println("capacity: " + buffer.capacity());
System.out.println("mark: " + buffer);

buffer.put("123".getBytes());

System.out.println("-------------put:123......");
System.out.println("mark: " + buffer);

buffer.flip(); //读写交替

System.out.println("-------------flip......");
System.out.println("mark: " + buffer);

buffer.get();

System.out.println("-------------get......");
System.out.println("mark: " + buffer);

buffer.compact();

System.out.println("-------------compact......");
System.out.println("mark: " + buffer);

buffer.clear();

System.out.println("-------------clear......");
System.out.println("mark: " + buffer);

}


}