有什么方法可以将文件内容映射到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
SEC_IMAGE
属性,则可以删除映射文件:@eryksun
>使用FILE_FLAG_DELETE_ON_CLOSE
标志打开文件-该文件是
在关闭所有句柄后立即删除
包括指定的句柄以及任何其他打开或重复的句柄
处理.或者我们可以使用NtOpenFile
或NtCreateFile
呼叫带有标志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();