java-在Windows中使用SHARE属性对文件进行内存映射(因此未锁定文件以防删除)

前端之家收集整理的这篇文章主要介绍了java-在Windows中使用SHARE属性对文件进行内存映射(因此未锁定文件以防删除) 前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

有什么方法可以将文件内容映射到Windows中不持有文件锁的内存中(特别是可以在仍然映射时删除文件)?

Java NIO库在Windows中以这样一种方式mmap文件,使得在堆中留下任何未经垃圾回收的MappedByteBuffer引用时,无法删除映射文件. JDK团队声称这是Windows的局限性,但是仅当文件被mmap时才出现,而当它们作为常规文件打开时则没有:

https://mail.openjdk.java.net/pipermail/nio-dev/2019-January/005698.html

(显然,如果在mmap’d期间删除文件,则在Windows文件语义世界中,对于mmap’d区域应该发生的确切情况是值得商bat的,尽管在Linux中已经定义好了.)

作为参考,在内存映射(或尚未垃圾回收)的情况下无法删除文件会在Java中造成很多问题:

http://www.mapdb.org/blog/mmap_files_alloc_and_jvm_crash/

出于安全原因,不支持取消映射操作:

https://bugs.openjdk.java.net/browse/JDK-4724038

更新:另请参见:How to unmap an mmap’d file by replacing with a mapping to empty pages

最佳答案
如前所述,如果通过2种方式创建的部分(文件映射)没有SEC_IMAGE属性,则可以删除映射文件@eryksun

>使用FILE_FLAG_DELETE_ON_CLOSE标志打开文件-该文件
关闭所有句柄后立即删除
包括指定的句柄以及任何其他打开或重复的句柄
处理.或者我们可以使用NtOpenFileNtCreateFile
呼叫带有标志FILE_DELETE_ON_CLOSE.
>致电ZwDeleteFile.真的internal NtDeleteFile已打开
带有FILE_DELETE_ON_CLOSE标志和特殊内部文件文件
性格DeleteOnly = TRUE.这是更多致电
高效比较正常的打开文件,然后关闭它的句柄.

代码中看起来像这样.

#ifndef FILE_SHARE_VALID_FLAGS
#define FILE_SHARE_VALID_FLAGS 0x00000007
#endif

NTSTATUS Delete1(PCWSTR FileName)
{
    HANDLE hFile = CreateFile(FileName,DELETE,FILE_SHARE_VALID_FLAGS,OPEN_EXISTING,FILE_FLAG_DELETE_ON_CLOSE,0);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return RtlGetLastNtStatus();
    }
    CloseHandle(hFile);
    return 0;
}

NTSTATUS Delete2(PCWSTR FileName)
{
    UNICODE_STRING ObjectName;

    if (RtlDosPathNameToNtPathName_U(FileName,&ObjectName,0))
    {
        OBJECT_ATTRIBUTES oa = { sizeof(oa),&ObjectName };

        NTSTATUS status = ZwDeleteFile(&oa);

        RtlFreeUnicodeString(&ObjectName);

        return status;
    }

    return STATUS_UNSUCCESSFUL;
}

请注意,呼叫DeleteFileW在这里失败,状态为STATUS_CANNOT_DELETE.我建议在这里而不是GetLastError()调用RtlGetLastNtStatus(),因为Win32将NTSTATUS映射到错误代码不是可注入的,并且经常丢失有价值的信息.说STATUS_CANNOT_DELETE映射到ERROR_ACCESS_DENIED.但是存在另一个巨大的NTSATUS代码,它们也映射到ERROR_ACCESS_DENIED. ERROR_ACCESS_DENIED不仅是STATUS_ACCESS_DENIED(拒绝实际访问).比较ERROR_ACCESS_DENIED,获得了STATUS_CANNOT_DELETE更多信息. RtlGetLastNtStatus具有与GetLastError完全相同的签名,并从ntdll.dll导出(因此包括ntdll.lib或ntdllp.lib)

extern "C" NTSYSCALLAPI NTSTATUS NTAPI RtlGetLastNtStatus();

猜你在找的Java相关文章