使用 TRUNCATE_EXISTING 调用 Windows 的 CreateFile 和使用 OPEN_EXISTING 调用然后调用 SetEndOfFile 有什么区别?
前者被记录为需要 GENERIC_WRITE 访问权限,如果我只要求 FILE_WRITE_DATA,CreateFile 将失败并显示 ERROR_ACCESS_DENIED。
对于后者,FILE_WRITE_DATA 就足够了,CreateFile 和 SetEndOfFile 都成功。
最佳答案
FILE_WRITE_DATA
是单存取位(2)。当GENERIC_WRITE
是通用访问,映射到 FILE_GENERIC_WRITE
中的案例文件中你可以查看它的定义:
#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE |\
FILE_WRITE_DATA |\
FILE_WRITE_ATTRIBUTES |\
FILE_WRITE_EA |\
FILE_APPEND_DATA |\
SYNCHRONIZE)
所以除了FILE_WRITE_DATA
还包括FILE_WRITE_ATTRIBUTES
, FILE_WRITE_EA
, FILE_APPEND_DATA
和READ_CONTROL==STANDARD_RIGHTS_WRITE
。 ( CreateFile
始终隐式要求 SYNCHRONIZE
)
如果你有ERROR_ACCESS_DENIED
对于 GENERIC_WRITE
但对于 FILE_WRITE_DATA
来说还可以这意味着您有 FILE_WRITE_DATA
访问文件,但没有来自 FILE_GENERIC_WRITE
的一些额外访问权限。这种情况很少见,但也有可能发生。
但实际上截断文件所需的只是 FILE_WRITE_DATA
使用权。这是错误,而且 win32 api 的设计非常糟糕 CreateFile
.
要将文件截断为零大小,我们可以使用或:
-
NtSetInformationFile
与FileEndOfFileInformation
(这 调用者必须使用FILE_WRITE_DATA
打开文件标志设置 在 DesiredAccess 参数中)或FileAllocationInformation
- 这适用于所有窗口 SetFileInformationByHandle
- 非常薄的win32 shellNtSetInformationFile
但仅适用于 Vista。和FileEndOfFileInfo
或FileAllocationInfo
。请注意,如果我们设置AllocationSize
to 0 -- 文件也将被截断为 0 大小。The end-of-file (EOF) position for a file must always be less than or equal to the file allocation size. If the allocation size is set to a value that is less than EOF, the EOF position is automatically adjusted to match the file allocation size.
SetEndOfFile
第一次调用ZwQueryInformationFile
和FilePositionInformation
(文件句柄打开后立即设置为 0) 然后使用它(FILE_POSITION_INFORMATION
)进行两次调用NtSetInformationFile
两者都有FileEndOfFileInformation
和FileAllocationInformation
。显然在这种情况下我们有 2 个不 需要对内核进行额外的调用。所以这比较前2效率不高 方法。CreateFile
与TRUNCATE_EXISTING
首先打开文件然后 调用NtSetInformationFile
与FileAllocationInformation
放 到 0。但是这个调用,你如何查看需要额外的访问权限 -FILE_GENERIC_WRITE
这确实不需要。只需要FILE_WRITE_DATA
。所以这种方式不好- 使用
NtCreateFile
与FILE_OVERWRITE
CreateDisposition - 它在单个调用中打开文件并将 EOF 设置为 0。根据感觉TRUNCATE_EXISTING
必须这样做(使用FILE_OVERWRITE
处置)。但由于未知的原因(我认为这是错误)它使用FILE_OPEN
通过额外的调用来访问NtSetInformationFile
与FileAllocationInformation
- 如果我们不仅需要截断现有文件,还需要创建新文件
空文件,如果尚不存在 - 最好使用
FILE_OVERWRITE_IF
选项或对应的CREATE_ALWAYS
- 这也开放和 在对内核的单次调用中截断文件。或创建新文件
关于winapi - TRUNCATE_EXISTING 与 OPEN_EXISTING+SetEndOFile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49457814/