MappedByteBuffer使用注意点
(2011-08-10 11:05:53)
标签: it |
最近使用MD5进行大文件验证,固使用NIO这种高效率的模式来进行文件映射:
Java代码
- FileInputStream in = newFileInputStream(file);
- FileChannel ch = in.getChannel();
- MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY,0, file.length());
- messageDigest.update(byteBuffer);
- String md5 = bufferToHex(messageDigest.digest());
- ch.close();
- in.close();
本来想如果文件md5与数据库存储的值不同就删掉该文件的,结果出现了文件无法删除的情况。
抛出的违例
java.io.FileNotFoundException: E:\hello.jar (请求的操作无法在使用用户映射区域打开的文件上执行。)
后来经查,原来是当使用 FileChannel.map 方法时,MappedByteBuffer 已经在系统内占用了一个句柄,而使用 FileChannel.close 方法是无法释放这个句柄的,且FileChannel有没有提供类似 unmap 的方法,因此会出现无法删除文件的情况。
此问题一直让我很郁闷,后来到网上查询到两种方法...
第一种:
Java代码
- AccessController.doPrivileged(newPrivilegedAction() {
-
publicObject run() { -
try{ -
Method getCleanerMethod = buffer.getClass().getMethod("cleaner",newClass[0]); -
getCleanerMethod.setAccessible(true); -
sun.misc.Cleaner cleaner = (sun.misc.Cleaner) -
getCleanerMethod.invoke(byteBuffer,newObject[0]); -
cleaner.clean(); -
} catch(Exception e) { -
e.printStackTrace(); -
} -
returnnull; -
} - });
publicstaticvoid clean(ByteBuffer bb){
if(bb== null)return;
Cleaner cleaner= ((DirectBuffer) bb).cleaner();
if(cleaner !=null) cleaner.clean();
}
此种方法需要JDK支持,我用的是JRE 1.6,提示没有 sun.misc.Cleaner 类,JDK包太大,项目又不让用。
第二种方法是显性设置byteBuffer为null,并调用GC,没什么实际意义。
实在没招了,又回来使用InputStream了...
Java代码
- FileInputStream in = newFileInputStream(file);
- ByteArrayOutputStream out = newByteArrayOutputStream((int)file.length());
- byte[] cache =newbyte[1048576];
- for(inti = in.read(cache);i != -1;i = in.read(cache)){
-
out.write(cache, 0, i); - }
- in.close();
- out.close();
- messageDigest.update(out.toByteArray());
- md5 = bufferToHex(messageDigest.digest());