在UNIX中,如果我以附加模式打开文件,如
fd = open("filename", O_APPEND);
然后给出这样的文件描述符,可以使用fcntl
轻松找出它打开的标志:
fcntl(fd, F_GETFL) & O_APPEND
我知道Windows上没有fcntl
,但我想知道是否有某种方法可以确定这一点。 Windows确实支持附加模式,例如在使用CreateFile
创建文件并传入FILE_APPEND_DATA
标记时。
但是,如果我拥有的是已经打开的文件的句柄,我就无法找到一种方法来确定首次打开文件时请求的访问权限。 This question提供了检查特定文件访问权限的基本方法,但这似乎没有帮助。我试过了,即使我打开一个只读模式的文件,它仍然告诉我,我有FILE_APPEND_DATA
访问文件,如果我要求它。换句话说,此方法仅告诉我该进程对特定文件具有哪些访问权限(继承自启动该进程的用户)。它没有说明文件打开时请求的确切访问权限。
这与Windows如何跟踪文件是否只应附加到无关。这是后一个问题,我找不到任何答案。我发现最接近的是GetFileInformationByHandleEx但是在梳理完文档之后,没有一个文件属性可以通过该API返回,表示“附加模式”。
更新:为了更好地澄清我的问题,这个问题实际上只适用于MS VC运行时库 - 使用类似POSIX的函数_open
打开的文件并写入fwrite
等。看来本机win32文件句柄没有“附加模式”的概念。
答案 0 :(得分:3)
对于 Windows 视为处于“追加”模式的文件,这将有效:
使用半文档化的NtQueryInformationFile
系统调用(从ntdll.dll
导出)来查询FILE_ACCESS_INFORMATION
。这应该告诉你打开文件的访问掩码,它应该包含FILE_APPEND_DATA
。
对于 C运行时以“追加”模式打开的文件,但这不起作用,因为Windows实际上并未在追加模式下打开它。这样做的方法是以某种方式将文件描述符转换为文件对象,并检查那里的标志 - 但是没有记录的方法来执行此操作。
您可以查看Visual C ++ CRT源代码以了解如何执行此操作...可能有某种方法可以访问描述符所在的数组,但我不确定如何。
CRT中的代码似乎是_pioinfo(fd)->osfile |= FAPPEND
,所以希望这会有所帮助。
答案 1 :(得分:3)
FileMode.Append是.NET Framework团队想象力的一个虚构。它不是Windows支持的模式。他们添加它以使原生winapi CreateFile()函数(FileStream)的包装更容易使用。 FileMode是其dwCreationDisposition参数的枚举包装器。哪个没有CREATE_APPEND选项。
FileStream.Init()方法中最相关的代码是:
bool seekToEnd = (mode==FileMode.Append);
// Must use a valid Win32 constant here...
if (mode == FileMode.Append)
mode = FileMode.OpenOrCreate;
换句话说,FileMode.Append与有效的CreateFile()选项不匹配,必须进行映射。如果存在则将打开该文件,否则将创建该文件。它负责额外的操作,打开文件后,它会寻找到文件的末尾。当您附加到现有文件时,您当然希望这样。存在一些额外的错误检查,它还确保您打开文件进行写入。
因此,在你的追求中发现了一个洞,以便发现这一点。 GetFileInformationByHandleEx()winapi函数可用于恢复文件状态。 Mehrdad未记录的原生api调用的记录功能。您可以从FileDispositionInfo返回dwCreationDisposition参数,以检查它是否为OpenOrCreate。但是,不唯一,它也可以从使用客户端代码中的FileMode.OpenOrCreate打开的文件开始。很少见,但可能。
你失去的是寻找文件末尾的记忆。您可以使用FileStream.Position属性,但这当然会受到同时写入的任何影响。如果确实很重要,那么做必须保留使用的FileMode值。
答案 2 :(得分:2)
自我回答,感谢@mehrdad和@HansPassant指出我正确的方向。实际上,MSVCRT导出一个名为ioinfo
的结构数组,其中存储有关进程中每个打开文件句柄的信息。
结构的确切内容取决于VC版本和一些定义,但一般来说它的前两个成员是定义的:
typedef struct {
intptr_t osfhnd; /* underlying OS file HANDLE */
char osfile; /* attributes of file (e.g., open in text mode?) */
....
} ioinfo;
osfile
成员很有意思 - 如果使用_O_APPEND
打开文件,则会在此设置名为FAPPEND
的{{1}}标记。
我在Python中基于CPython的posixmodule中的类似代码编写了一个小实用程序函数,可以执行此检查:https://gist.github.com/embray/6444262
答案 3 :(得分:2)
(我知道这是2013年以来的一个非常老的问题,但是我想与所有想直接从Windows File Handle获取文件模式 [读取,写入,APPEND] 的人分享我的解决方案)
NtQueryInformationFile API实际上可以为您提供足够的信息,以确定文件处于哪种模式。
让我们使用以下代码进行演示:
IO_STATUS_BLOCK statusBlock;
FILE_ACCESS_INFORMATION accessInfo;
// You have to import this API by yourself using LoadLibary and GetProcAddress
auto status = NtQueryInformationFile(
yourFileHandle, &statusBlock, &accessInfo,
sizeof(FILE_ACCESS_INFORMATION), (FILE_INFORMATION_CLASS)8);
auto flags = accessInfo.AccessFlags;
// true if in read mode, otherwise false
auto isRead = (FILE_READ_DATA & flags) != 0;
// true if in write mode, otherwise false
auto isWrite = (FILE_WRITE_DATA & flags) != 0;
// true if in write mode or append mode
// (I think these 2 modes are mutual exclusive), otherwise false
auto isAppend = (FILE_APPEND_DATA & flags) != 0;
实际上非常简单:
读取模式本身不会打开FILE_APPEND_DATA标志,附加模式本身不会打开FILE_WRITE_DATA标志。
我希望这可以帮助其他人。