`
coderplay
  • 浏览: 577950 次
  • 性别: Icon_minigender_1
  • 来自: 广州杭州
社区版块
存档分类
最新评论

文件在使用FileChannel.map后不能被删除(Windows上)

    博客分类:
  • java
阅读更多
同事发现在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!
分享到:
评论
3 楼 bohc 2018-03-29  
谢谢,搞了两天了,现在才算是找到问题所在,解决了。
2 楼 zhangyifan_614 2013-03-01  
感觉反射调用Cleaner的clean方法会更好些!
因为他可以封装包括unmap在内的所有释放资源的操作!
1 楼 huijie 2013-02-27  
也碰到相同问题了

相关推荐

    有效率的读取大文件(2G)

    MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, raf.length()); // 使用map直接访问文件内容 raf.close(); ``` 6. **使用大数据处理框架**:对于超大型文件,可以考虑使用Hadoop、Spark等...

    【IT十八掌徐培成】Java基础第26天-06.FileChannel-RandomAccessFile-CopyFile.zip

    在Java编程语言中,`FileChannel`和`RandomAccessFile`是两个重要的I/O类,它们主要用于处理磁盘文件。这两个类提供了高级的文件操作功能,例如高效的数据传输和随机访问文件内容。在这个主题中,我们将深入探讨这两...

    java nio 写文件

    通过`FileChannel.map()`方法,可以直接将文件映射到内存中,这样读写文件就像操作内存一样快速。但需要注意的是,内存映射文件可能会消耗大量内存,因此对于大文件操作要谨慎使用。 5. **选择器(Selectors)** ...

    java 模拟windows文件操作

    在Java编程语言中,模拟Windows文件操作是一项常见的任务,它涉及到对文件和目录的创建、读取、写入、删除等基本操作。Java提供了一套完整的API,即Java IO(输入/输出)和NIO(非阻塞I/O),使得开发者能够方便地...

    java按行读取大文件并解析入库

    为了高效地处理这类问题,我们可以利用Java的`java.nio`包中的BufferedReader和FileChannel等类,实现按行读取大文件,并将其内容解析后存储到数据库中。本文将详细讲解这一过程。 首先,我们需要了解`java.nio`包...

    java读取超大文本文件

    - `FileChannel.map()`方法用于创建文件的内存映射,参数包括模式(如只读)、起始位置及长度。 - `MappedByteBuffer`可以直接在内存中操作数据,提高性能。 - 通过循环读取内存映射文件的不同部分,可以处理任意...

    Java在Windows下导出xml文件到Linux服务器上

    在Java编程环境中,将XML文件从Windows系统导出并传输到Linux服务器是一项常见的任务,尤其在分布式系统和跨平台操作的场景中。本篇将详细阐述这个过程中的关键知识点,包括路径处理、文件操作以及远程文件系统的...

    java 读取文件方法的总结

    如果需要在文件的任意位置开始读取,可以使用`RandomAccessFile`类。它可以设置文件指针的位置,然后从那里开始读取数据。例如: ```java RandomAccessFile raf = new RandomAccessFile(fileName, "r"); raf....

    java NIO原理和使用

    MappedByteBuffer mappedBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size()); ``` 在这个例子中,我们将整个文件映射到了内存中,并设置了读写权限。 #### 三、Java NIO 使用实例 ...

    java nio 读文件

    在Java NIO中,读取文件主要涉及FileChannel和ByteBuffer。以下是一个简单的示例: ```java import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio....

    OpenJDK11U-jdk_x64_windows_11.0.13_8.zip

    9. **弃用NIO的FileChannel.map()方法**:出于安全性考虑,不再推荐直接映射大文件到内存,建议使用其他方式读写文件。 10. **IPv6地址支持改进**:增强了对IPv6地址的处理,尤其是环回地址的处理。 在安装和使用...

    文件管理器实现

    在Android平台上,实现一个文件管理器涉及到多个关键知识点,这些知识点包括但不限于文件系统的理解、Android权限管理、Intent机制、URI转换以及自定义文件选择器。下面我们将深入探讨这些内容。 首先,Android文件...

    读大文件Java

    MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); ``` 内存映射文件将文件的部分或全部映射到内存,无需实际加载所有数据,降低了内存压力。 5. **流式处理和Spliterator**: ...

    commons-mmf.rar_java nio_java共享内存_共享内存

    在Java中,使用`FileChannel.map()`方法创建`MappedByteBuffer`对象,这个方法需要`FileChannel`、文件的起始偏移量和映射的长度作为参数。一旦创建了映射,就可以像操作普通`ByteBuffer`一样对它进行读写操作。例如...

    java高速文件缓存

    MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize); ``` 四、第三方库:Guava Cache Google的Guava库提供了一套完善的缓存解决方案,支持自定义过期时间、大小限制等。Guava ...

    java的IO流实现文件复制20190726.zip

    在文件复制中,我们通常使用FileInputStream和FileOutputStream。 首先,我们需要创建FileInputStream对象,将源文件作为参数传入构造函数。然后,创建一个FileOutputStream对象,传入目标文件的路径。接着,我们...

    java 使用IO流实现文件的复制

    在这个例子中,我们使用`FileChannel`的`transferTo()`方法直接将源文件通道的数据传输到目标文件通道,避免了中间的缓冲区操作,提高了效率。 总的来说,Java通过IO流提供了多种文件复制的方法,开发者可以根据...

    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`文件名列表中,...

    NIO复制文件

    3. **异常处理**:在上述代码中,我们使用了try-with-resources语句来确保资源在使用后能够正确关闭,避免资源泄露。同时,我们捕获并处理了可能的`IOException`,这是处理I/O操作时的标准做法。 4. **性能优化**:...

Global site tag (gtag.js) - Google Analytics