解释:将文件的一段区域映射到内存中,比传统的文件处理速度要快很多
参考:
无格式输入流 110秒
缓冲输入流 9.9秒
随机存取文件 162秒
内存映射文件 7.2秒
例子
Java代码
1. package twelve;
2.
3. import java.io.BufferedInputStream;
4. import java.io.FileInputStream;
5. import java.io.FileNotFoundException;
6. import java.io.IOException;
7. import java.io.InputStream;
8. import java.io.RandomAccessFile;
9. import java.nio.MappedByteBuffer;
10. import java.nio.channels.FileChannel;
11. import java.util.zip.CRC32;
12.
13. /**
14. @Title NIOTTest.java
15. @description TODO
16. @author qinpeng
17. @date Aug 25, 2009 10:23:26 PM
18. */
19. public class NIOTTest {
20.
21. public static void main(String[] args) {
22.
23. "d:\\IOTest.pdf";
24.
25. "inputStream");
26. long start = System.currentTimeMillis();
27. long crcValue = checksumInputStreanm(fileName);
28. long end = System.currentTimeMillis();
29. System.out.println(Long.toHexString(crcValue));
30. "耗时");
31.
32. "BufferedinputStream");
33. start = System.currentTimeMillis();
34. crcValue = checksumInputStreanm(fileName);
35. end = System.currentTimeMillis();
36. System.out.println(Long.toHexString(crcValue));
37. "耗时");
38.
39. "RandomAccessFileinputStream");
40. start = System.currentTimeMillis();
41. crcValue = checksumInputStreanm(fileName);
42. end = System.currentTimeMillis();
43. System.out.println(Long.toHexString(crcValue));
44. "耗时");
45.
46. " MappedFile inputStream");
47. start = System.currentTimeMillis();
48. crcValue = checksumInputStreanm(fileName);
49. end = System.currentTimeMillis();
50. System.out.println(Long.toHexString(crcValue));
51. "耗时");
52. }
53.
54.
55.
56. public static long checksumInputStreanm(String fileName){
57. new CRC32();
58. try {
59. new FileInputStream(fileName);
60. int c;
61. while((c=in.read())!=-1){
62. crc.update(c);
63. }
64. catch (FileNotFoundException e) {
65. e.printStackTrace();
66. "NIOTTest--checksumInputStreanm--new FileInputStream is not found");
67. catch(IOException ioe){
68. ioe.printStackTrace();
69. "NIOTTest--checksumInputStreanm--new FileInputStream'read append IOException");
70. }
71. return crc.getValue();
72. }
73.
74. public static long checksumBufferedInputStream(String fileName){
75. new CRC32();
76. try {
77. new BufferedInputStream(new FileInputStream(fileName));
78. int c;
79. while((c=in.read())!=-1){
80. crc.update(c);
81. }
82. catch (FileNotFoundException e) {
83. e.printStackTrace();
84. "NIOTTest--checksumBufferedInputStream--new FileInputStream is not found");
85. catch(IOException ioe){
86. ioe.printStackTrace();
87. "NIOTTest--checksumBufferedInputStream--new FileInputStream'read append IOException");
88. }
89. return crc.getValue();
90. }
91.
92.
93. public static long checksumRondomAccessFileInputStream(String fileName){
94. new CRC32();
95. try {
96. new RandomAccessFile(fileName,"r");
97. int c;
98. while((c=file.read())!=-1){
99. crc.update(c);
100. }
101. catch (FileNotFoundException e) {
102. e.printStackTrace();
103. "NIOTTest--checksumRondomAccessFileInputStream--new FileInputStream is not found");
104. catch(IOException ioe){
105. ioe.printStackTrace();
106. "NIOTTest--checksumRondomAccessFileInputStream--new FileInputStream'read append IOException");
107. }
108. return crc.getValue();
109. }
110.
111. public static long checksumMappedFile(String fileName){
112. new CRC32();
113. try {
114. new FileInputStream(fileName);
115. FileChannel channel = in.getChannel();
116. int length = (int) channel.size();
117. 0, length);
118.
119. for(int p = 0;p<length;p++){
120. int c = buffer.getInt(p);
121. crc.update(c);
122. }
123. catch (FileNotFoundException e) {
124. e.printStackTrace();
125. "NIOTTest--checksumRondomAccessFileInputStream--new FileInputStream is not found");
126. catch(IOException ioe){
127. ioe.printStackTrace();
128. "NIOTTest--checksumRondomAccessFileInputStream--new FileInputStream'read append IOException");
129. }
130. return crc.getValue();
131. }
132.
133.
134. }
------------------------------------------------------------------------------------------------------------------
内存映射文件(memory-mapped file)能让你创建和修改那些大到无法读入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问了。这种解决思路能大大简化修改文件的代码。下面就是一个简单的例子:
代码
1. import
2. import
3. import
4. public class
5. static int length = 0x8FFFFFF; // 128 Mb
6. public static void main(String[] args) throws
7. MappedByteBuffer out =
8. new RandomAccessFile("test.dat", "rw").getChannel()
9. 0, length);
10. for(int i = 0; i < length; i++)
11. byte)'x');
12. "Finished writing");
13. for(int i = length/2; i < length/2 + 6; i++)
14. char)out.get(i));
15. }
16. }
为了能以读写的方式打开文件,我们从RandomAccessFile入手。拿到channel之后,我们用map( )方法生成了一个MappedByteBuffer。这是一种特殊的"direct buffer"。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大;也就是说,它还可以映射一个大文件的某个小片断。
MappedByteBuffer是ByteBuffer的派生类,因此它具备了ByteBuffer的所有方法。这里只简单地演示了一下put( )和get( )方法,除此之外,你还可以使用asCharBuffer( )之类的方法。
上述例程创建了一个128MB的文件,或许这已经超出OS的允许范围了。文件的访问好像只是一瞬间的事,这是因为,真正调入内存的只是其中的一小部分,其余部分则被放在交换文件上。这样你就可以很方便地修改超大型的文件了(最大可以到2 GB)。
注意,Java是调用操作系统的"文件映射机制(file-mapping facility)"来提升性能的。
由于Java的文件锁是直接映射操作系统的锁机制的,因此其它进程也能看到文件锁。
虽然你可以用wrap( ) 直接把char数组转换成CharBuffer,但实际上它还是一个ByteBuffer,而CharBuffer只是它的view。由此可知,我们操控的对象永远都是ByteBuffer,因为只有它才能往channel里读写数据。
一般来说,你是不会让两个进程去共享一个网络socket的。)tryLock( ) 是非阻塞的。它会试着去获取这个锁,但是如果得不到(其它进程已经以独占方式得到这个锁了),那它就直接返回。而lock( )是阻塞的。如果得不到锁,它会在一直处于阻塞状态,除非它得到了锁,或者你打断了调用它(即lock( )方法)的线程,或者关闭了它要lock( )的channel,否则它是不会返回的。最后用FileLock.release( )释放锁。
还可以像这样锁住文件的某一部分
tryLock(long position, long size, boolean shared)
或者
lock(long position, long size, boolean shared)
这个方法能锁住文件的某个区域(size - position)。
其中第三个参数表示锁能不能共享。
虽然在修改文件的过程中,无参数的lock( )和tryLock( )方法的锁定范围会随文件大小的变化,带参数的方法却不行。如果你锁住了position到position+size这段范围,而文件的长度又增加了,那么position+size后面是不加锁的。而无参数的lock方法则会锁定整个文件,不管它变不变长。
锁是独占的还是共享的,这要由操作系统来决定。如果操作系统不支持共享锁,而程序又申请了一个,那么它会返回一个独占锁。你可以用FileLock.isShared( )来查询锁的类型(共享还是独占)。