首页 > 解决方案 > 将最后 N 个字节写入使用 FILE_FLAG_NO_BUFFERING 打开的文件

问题描述

在将大量顺序数据写入磁盘时,我发现有一个内部 4MB 缓冲区,并且在打开文件进行写入时我指定了[FILE_FLAG_NO_BUFFERING][1],以便使用我的内部缓冲区。

但这也产生了写入完整扇区块(我的机器上为 512 字节)的要求。

如何将最后 N<512 个字节写入磁盘?

WriteFile 是否有一些标志允许这样做?

我是否用额外的NUL字符填充它们,然后将文件大小截断到正确的值?(有SetFileValidData还是类似的?)

对于那些想知道尝试这种方法的原因的人。我们的应用程序记录了很多。为了处理这个问题,存在一个专门的日志线程,它可以格式化日志并将其写入磁盘。此外,如果我们以最完整的细节记录,我们每秒记录的数据可能会超出磁盘系统的处理能力。(对于 SAN 系统调整不佳的客户,通常会注意到这一点。)

因此,目标是尽可能多地写入日志,但也要注意我们何时开始使系统超载,然后稍作保留,例如减少日志的详细信息。
因此,有一个想法是填充一个大内存块并将其提供给操作系统,希望减少开销。

标签: winapioutput-bufferingwritefileio-buffering

解决方案


正如评论所暗示的那样,以这种方式编写文件可能不是现实世界情况的最佳解决方案。但是如果FILE_FLAG_NO_BUFFERING使用 write with,
SetFileInformationByHandle是标记文件比整个块短的方法。

int data_len = len(str);
int len_last_block = BLOCKSIZE%datalen;
int padding_to_fill_block = (data_last_block == BLOCKSIZE ? 0 : (BLOCKSIZE-len_last_block);
str.append('\0', padding_to_fill_block);

ULONG bytes_written = 0;
::WriteFile(hFile, data, data_len+padding_to_fill_block, &bytes_written, NULL));
m_filesize += bytes_written;;

LARGE_INTEGER end_of_file_pos;
end_of_file_pos.QuadPart = m_filesize - padding_to_fill_block;
if (!::SetFileInformationByHandle(hFile, FileEndOfFileInfo, &end_of_file_pos, sizeof(end_of_file_pos)))
{
    HRESULT hr = ::GetLastErrorMessage();
}

推荐阅读