同事发现在Windows上使用FileChannel的map方法之后, 不能够删除掉文件. 我在Linux上试了一下, 发现没这个问题。 做个笔记, 记录一下.
import java.io.File;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import sun.nio.ch.FileChannelImpl;
public class TestDeleteMappedFile {
public static void main(String args[]) {
File f = new File("mapfile");
RandomAccessFile aFile = null;
FileChannel inChannel = null;
try {
aFile = new RandomAccessFile(f, "rw");
inChannel = aFile.getChannel();
ByteBuffer buf = inChannel.map(MapMode.READ_WRITE, 0L, 4);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
inChannel.close();
aFile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("delete " + f + " : " + f.delete());
}
}
从
Oracle的buglist上看到了这个问题的描述.
引用
We cannot fix this. Windows does not allow a mapped file to be deleted. This
problem should be ameliorated somewhat once we fix our garbage collectors to
deallocate direct buffers more promptly (see 4469299), but otherwise there's
nothing we can do about this.
sun.misc.Cleaner为我们干了关闭文件, 释放资源的脏活. 这个类是一个幻引用, 所以会在gc的时候调用到. FileChannel正是调用了这个Cleaner, 在gc的时候做unmap.
// sun.nio.ch.FileChannelImpl类
Unmapper um = new Unmapper(addr, size + pagePosition);
if ((!writable) || (imode == MAP_RO))
return Util.newMappedByteBufferR(isize, addr + pagePosition, um);
// java.nio.DirectByteBuffer类
// For memory-mapped buffers -- invoked by FileChannelImpl via reflection
//
protected DirectByteBuffer(int cap, long addr, Runnable unmapper) {
super(-1, 0, cap, cap, true);
address = addr;
cleaner = Cleaner.create(this, unmapper);
viewedBuffer = null;
}
如果finalizer delay的时候不能调unmap, 那么手动调unmap, 应该就可以在windows上释放掉资源了. 我们试试
import java.io.File;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import sun.nio.ch.FileChannelImpl;
public class TestDeleteMappedFile {
public static void main(String args[]) {
File f = new File("mapfile");
RandomAccessFile aFile = null;
FileChannel inChannel = null;
try {
aFile = new RandomAccessFile(f, "rw");
inChannel = aFile.getChannel();
ByteBuffer buf = inChannel.map(MapMode.READ_WRITE, 0L, 4);
// 加上这几行代码,手动unmap
Method m = FileChannelImpl.class.getDeclaredMethod("unmap", MappedByteBuffer.class);
m.setAccessible(true);
m.invoke(FileChannelImpl.class, buf);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
inChannel.close();
aFile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("delete " + f + " : " + f.delete());
}
}
果然, 可以删除
Have fun!
分享到:
相关推荐
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, raf.length()); // 使用map直接访问文件内容 raf.close(); ``` 6. **使用大数据处理框架**:对于超大型文件,可以考虑使用Hadoop、Spark等...
在Java编程语言中,`FileChannel`和`RandomAccessFile`是两个重要的I/O类,它们主要用于处理磁盘文件。这两个类提供了高级的文件操作功能,例如高效的数据传输和随机访问文件内容。在这个主题中,我们将深入探讨这两...
通过`FileChannel.map()`方法,可以直接将文件映射到内存中,这样读写文件就像操作内存一样快速。但需要注意的是,内存映射文件可能会消耗大量内存,因此对于大文件操作要谨慎使用。 5. **选择器(Selectors)** ...
在Java编程语言中,模拟Windows文件操作是一项常见的任务,它涉及到对文件和目录的创建、读取、写入、删除等基本操作。Java提供了一套完整的API,即Java IO(输入/输出)和NIO(非阻塞I/O),使得开发者能够方便地...
为了高效地处理这类问题,我们可以利用Java的`java.nio`包中的BufferedReader和FileChannel等类,实现按行读取大文件,并将其内容解析后存储到数据库中。本文将详细讲解这一过程。 首先,我们需要了解`java.nio`包...
- `FileChannel.map()`方法用于创建文件的内存映射,参数包括模式(如只读)、起始位置及长度。 - `MappedByteBuffer`可以直接在内存中操作数据,提高性能。 - 通过循环读取内存映射文件的不同部分,可以处理任意...
在Java编程环境中,将XML文件从Windows系统导出并传输到Linux服务器是一项常见的任务,尤其在分布式系统和跨平台操作的场景中。本篇将详细阐述这个过程中的关键知识点,包括路径处理、文件操作以及远程文件系统的...
如果需要在文件的任意位置开始读取,可以使用`RandomAccessFile`类。它可以设置文件指针的位置,然后从那里开始读取数据。例如: ```java RandomAccessFile raf = new RandomAccessFile(fileName, "r"); raf....
MappedByteBuffer mappedBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size()); ``` 在这个例子中,我们将整个文件映射到了内存中,并设置了读写权限。 #### 三、Java NIO 使用实例 ...
在Java NIO中,读取文件主要涉及FileChannel和ByteBuffer。以下是一个简单的示例: ```java import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio....
9. **弃用NIO的FileChannel.map()方法**:出于安全性考虑,不再推荐直接映射大文件到内存,建议使用其他方式读写文件。 10. **IPv6地址支持改进**:增强了对IPv6地址的处理,尤其是环回地址的处理。 在安装和使用...
在Android平台上,实现一个文件管理器涉及到多个关键知识点,这些知识点包括但不限于文件系统的理解、Android权限管理、Intent机制、URI转换以及自定义文件选择器。下面我们将深入探讨这些内容。 首先,Android文件...
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); ``` 内存映射文件将文件的部分或全部映射到内存,无需实际加载所有数据,降低了内存压力。 5. **流式处理和Spliterator**: ...
在Java中,使用`FileChannel.map()`方法创建`MappedByteBuffer`对象,这个方法需要`FileChannel`、文件的起始偏移量和映射的长度作为参数。一旦创建了映射,就可以像操作普通`ByteBuffer`一样对它进行读写操作。例如...
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize); ``` 四、第三方库:Guava Cache Google的Guava库提供了一套完善的缓存解决方案,支持自定义过期时间、大小限制等。Guava ...
在文件复制中,我们通常使用FileInputStream和FileOutputStream。 首先,我们需要创建FileInputStream对象,将源文件作为参数传入构造函数。然后,创建一个FileOutputStream对象,传入目标文件的路径。接着,我们...
在这个例子中,我们使用`FileChannel`的`transferTo()`方法直接将源文件通道的数据传输到目标文件通道,避免了中间的缓冲区操作,提高了效率。 总的来说,Java通过IO流提供了多种文件复制的方法,开发者可以根据...
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); ``` 4. **使用Files类**: Java 7引入的`java.nio.file.Files`类提供了一些方便的静态方法,可以直接读取文件内容: ```java...
在这个例子中,我们创建了一个`FileChannel`实例用于写入合并后的文件,然后遍历所有输入文件,使用`FileChannel`读取每个文件的内容,并写入到输出文件中。 **3. FileUtils类** 在给定的`FileUtils`文件名列表中,...
3. **异常处理**:在上述代码中,我们使用了try-with-resources语句来确保资源在使用后能够正确关闭,避免资源泄露。同时,我们捕获并处理了可能的`IOException`,这是处理I/O操作时的标准做法。 4. **性能优化**:...