为什么这个实用程序方法会使文件锁定?

时间:2014-07-05 18:42:55

标签: java file file-io locking

我做了一个简单的实用工具方法来读取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
        }
    }
}

2 个答案:

答案 0 :(得分:2)

问题是GC没有清除bb,因此仍有对文件的引用。

内存映射文件的主要好处是,您可以避免将数据复制到byte []以使用它。如果你最后需要一个byte [],我建议你直接读取()直接进入byte []。

有一个内部方法

((DirectBuffer) bb).cleaner().clean();

释放内存映射。你必须非常确保在调用它之后你不会使用这个ByteBuffer。

答案 1 :(得分:1)

这里的问题是使用内存映射。顺便说一句,使用内存映射只是简单地将整个文件读入byte[]并不比使用FileInputStream的简单读取提供任何优势。

FileChannel.map州的文档:

  

[T]他缓冲并且它代表的映射将保持有效   直到缓冲区本身被垃圾收集。

     

映射一旦建立,就不依赖于文件通道   那是用来创造它的。特别是关闭频道没有   影响映射的有效性。

MappedByteBuffer的文档陈述类似的内容:

  

映射的字节缓冲区及其表示的文件映射保留   有效,直到缓冲区本身被垃圾收集。

这基本上意味着在MappedByteBuffer被垃圾收集之前,对文件的引用仍然存在。根据操作系统和FS,可以想象这种映射可以防止文件删除。