【问题标题】:WriteFile overlapped and fwrite equivalentWriteFile 重叠和 fwrite 等效
【发布时间】:2016-10-13 22:32:34
【问题描述】:

在 Windows 上,WriteFile() 函数有一个名为 lpOverlapped 的参数,可让您指定写入文件的偏移量。

我想知道,有没有类似的 fwrite() 跨平台?

我看到,如果使用rb+ 标志打开文件,我也许可以使用fseek() 写入特定偏移量。我的问题是 - 这种方法是否等同于重叠的WriteFile(),它会在所有平台上产生相同的行为吗?

背景

我需要这个的原因是因为我正在将阻塞的压缩数据流写入文件,并且我希望能够从文件中加载特定的块并能够解压缩它。因此,基本上,如果我跟踪块在文件中的开始位置,我可以加载块并以更有效的方式解压缩它。我知道可能有更好的方法可以做到这一点,但我需要这个解决方案来实现一些向后兼容性。

【问题讨论】:

  • fwrite 之前使用fseek
  • fwrite() 是 C stdio,而不是 C++ I/O。

标签: c++ file io


【解决方案1】:

假设您可以使用 POSIX 函数,而不仅仅是 C 或 C++ 标准库中的东西,那么解决方案是 pwrite(又名:定位写入)。

ssize_t rc = pwrite(file_handle, data_ptr, data_size, destination_offset);

【讨论】:

  • 注意:pwrite 更接近于write(2) 而不是fwrite(3)。但是,WriteFile 也是如此; pwritewriteWriteFile 基本上都是系统调用的瘦包装器,其中 fwrite 是更高级别的用户空间缓冲。
  • 我认为这正是 OP 在这里实际要求的,因为他已经在使用特定于 Windows 的 WriteFile 调用。
  • 亚尔。我想明确区分,答案没有错(我投了赞成票)。
【解决方案2】:

我认为您混淆了“重叠”和“覆盖”/“偏移”。我没有研究为什么微软明确表示重叠写入包含偏移参数的细节(我认为这是有道理的,如下所述)。通常,当 Microsoft 谈论“重叠”IO 时,他们谈论的是如何同步事件,例如开始写入文件、接收写入完成的通知以及开始对可能重叠或不重叠的文件的另一次写入 与先前的写入。在最后一种情况下,重叠是指您认为重叠的含义,即文件内容内的重叠。而微软的意思是写文件与你的线程运行时间重叠,或者不。请注意,如果多个线程可以写入同一个文件,这将变得非常复杂。

如果可能,当然如果你想要可移植的代码,你想避免所有这些废话,只在每个上下文中做最简单的编写,这意味着除非你真的需要性能,否则避免像“重叠 IO”这样的微软优化。 (如果您需要绝对最佳的性能,您可能希望自己缓存文件并管理重叠部分,然后从头到尾编写一次。)

【讨论】:

    【解决方案3】:

    虽然pwrite 可能是最好的解决方案,但还有一个替代方案可以使用stdio 函数。不幸的是,为了使其线程安全,您使用非标准的“stdio”来直接控制FILE* 的内部锁,并且名称不可移植。具体来说,POSIX 定义了one set of "take/release file lock" names,而Windows 定义了另一个集合(_lock_file/_unlock_file)。

    也就是说,您可以使用这些半便携式构造来使用stdio 函数来确保没有缓冲冲突(如果FILE* 缓冲区与pwrite 位置重叠,则pwritefileno(some_FILE_star) 可能会导致问题,因为pwrite 不会修复缓冲区):

    // Error checking omitted; you should actually check returns in real code
    size_t pfwrite(const void *ptr, size_t size, size_t n,
                   size_t offset, FILE *stream) {
        // Take FILE*'s lock and hold it for entire transaction
        flockfile(stream);  // _lock_file on Windows
    
        // Record position
        long origpos = ftell(stream);
    
        // Seek to desired offset and write
        fseek(stream, offset, SEEK_SET); // Possibly offset * size, not just offset?
        size_t written = fwrite(ptr, size, n, stream);
    
        // Seek back to original position
        fseek(stream, origpos, SEEK_SET);
    
        // Release FILE*'s lock now that transaction complete
        funlockfile(stream); // _unlock_file on Windows
        return written;
    }
    

    【讨论】:

    • 也感谢您。我不需要此应用程序的线程安全,但很高兴知道这一点。
    猜你喜欢
    • 1970-01-01
    • 2012-12-26
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多