MappedByteBufferのファイル削除の問題
Nioに詳しい友人は、MappedByteBufferがIOの効率を大幅に向上させたことを知っていますが、深刻な問題があります.
次のテストコードを参照してください.
Junitが実行された結果、断言に失敗し、ファイルの削除に成功しなかった.
解決策は、次のコードを追加することです.
次にtestDeleteFile()を次のように変更します.
Junitを再実行して成功!
これは、ファイルハンドルがクリアされず、MappedByteBufferによって占有され、外部で操作できないためです.クリアするには、GCが収集されるのを待たなければなりません.
SunはいつMappedByteBufferのunmapを提供できるか分からない!
このリンクにも注目してください:http://bugs.sun.com/view_bug.do?bug_id=4724038
次のテストコードを参照してください.
public class TestMappedByteBufferDeleteFile {
File testFile;
/**
*
* @throws URISyntaxException
* @throws IOException
*/
@Before public void createFile() throws URISyntaxException, IOException {
testFile = new File(this.getClass().getResource(".").getPath() + "/test.txt");
if(!testFile.exists()) {
testFile.createNewFile();
}
FileOutputStream fos = new FileOutputStream(testFile);
fos.write("TestMappedByteBufferDeleteFile".getBytes());
fos.close();
}
/**
* MappedByteBuffer
* @throws IOException
*/
@Test public void testDeleteFile() throws IOException {
map(testFile);
testFile.delete();
Assert.assertEquals(false, testFile.exists());
}
/**
* , MappedByteBuffer
* @param file
* @return
* @throws IOException
*/
public MappedByteBuffer map(File file) throws IOException {
FileInputStream in = new FileInputStream(file);
FileChannel ch = in.getChannel();
MappedByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
ch.close();
in.close();
return buffer;
}
}
Junitが実行された結果、断言に失敗し、ファイルの削除に成功しなかった.
解決策は、次のコードを追加することです.
/**
* MappedByteBuffer
* @param buffer
*/
public static void clean(final MappedByteBuffer buffer) {
if (buffer == null) {
return;
}
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
Method getCleanerMethod = buffer.getClass().getMethod(
"cleaner", new Class[0]);
if (getCleanerMethod != null) {
getCleanerMethod.setAccessible(true);
Object cleaner = getCleanerMethod.invoke(buffer,
new Object[0]);
Method cleanMethod = cleaner.getClass().getMethod(
"clean", new Class[0]);
if (cleanMethod != null) {
cleanMethod.invoke(cleaner, new Object[0]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
次にtestDeleteFile()を次のように変更します.
/**
* MappedByteBuffer clean
* @throws IOException
*/
@Test public void testDeleteFile() throws IOException {
MappedByteBuffer buffer = map(testFile);
clean(buffer);
testFile.delete();
Assert.assertEquals(false, testFile.exists());
}
Junitを再実行して成功!
これは、ファイルハンドルがクリアされず、MappedByteBufferによって占有され、外部で操作できないためです.クリアするには、GCが収集されるのを待たなければなりません.
SunはいつMappedByteBufferのunmapを提供できるか分からない!
このリンクにも注目してください:http://bugs.sun.com/view_bug.do?bug_id=4724038