我做了一个简单的实用工具方法来读取Java中的文件。不幸的是,该方法似乎在文件运行后将文件锁定。换句话说,即使在调用方法之后,并将其存储在byte []中,我也无法调用文件上的函数(例如.delete())。我很确定我关闭了所有频道。知道为什么文件之后无法删除?一个注意事项是当我调用.deleteOnExit()时删除文件。我知道我可以在Java 7 API中使用Files.read()方法,但我想知道为什么这个方法不起作用。任何建议都将不胜感激。
/**
* Converts the file into a byte[]. Also Android compatible. :)
* @param The File you want to get the byte[] from.
* @return The byte[]
* @throws IOException if something goes wrong in reading the file.
*/
private byte[] mapFileIn(File infile) throws IOException{
FileInputStream fis = null;
FileChannel fc = null;
try{
fis = new FileInputStream(infile);
fc = fis.getChannel(); // Get the file's size and then map it into memory
int sz = (int)fc.size();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz);
byte[] data2 = new byte[bb.remaining()];
bb.get(data2);
fc.close();
fis.close();
return data2;
}
finally{//Ensures resources are closed regardless of whether the action suceeded
try{
fis.close();
fc.close();
}
catch(Exception e){
//Does nothing
}
}
}
答案 0 :(得分:2)
问题是GC没有清除bb
,因此仍有对文件的引用。
内存映射文件的主要好处是,您可以避免将数据复制到byte []以使用它。如果你最后需要一个byte [],我建议你直接读取()直接进入byte []。
有一个内部方法
((DirectBuffer) bb).cleaner().clean();
释放内存映射。你必须非常确保在调用它之后你不会使用这个ByteBuffer。
答案 1 :(得分:1)
这里的问题是使用内存映射。顺便说一句,使用内存映射只是简单地将整个文件读入byte[]
并不比使用FileInputStream
的简单读取提供任何优势。
FileChannel.map州的文档:
[T]他缓冲并且它代表的映射将保持有效 直到缓冲区本身被垃圾收集。
映射一旦建立,就不依赖于文件通道 那是用来创造它的。特别是关闭频道没有 影响映射的有效性。
MappedByteBuffer的文档陈述类似的内容:
映射的字节缓冲区及其表示的文件映射保留 有效,直到缓冲区本身被垃圾收集。
这基本上意味着在MappedByteBuffer
被垃圾收集之前,对文件的引用仍然存在。根据操作系统和FS,可以想象这种映射可以防止文件删除。