可靠地计算磁盘已满时 fwrite 写入的字节数

Reliably counting bytes written by fwrite when disk is full

有谁知道一种可靠的方法来计算实际有多少字节 是否已使用 C 标准 I/O (fwrite) 在磁盘已满的情况下编写?

我在让它工作时遇到了很多麻烦。问题似乎是 fwrite 被缓冲,有时它认为它已经写了 比设备实际接受的字节多。

使用与设备块大小相同的小缓冲区,fwrite 将 报告它已经写入了一个完整的缓冲区,而实际上并没有,所以 count 最终比正确的多了一个块。我修好了 测试错误,只有在没有错误的情况下才添加到总数中。

但是,如果缓冲区更大,fwrite 会写入部分缓冲区, 我不会算那个。所以我检查了部分写入,添加 并跳出循环。结束了以下程序 (减少到 MCVE):

#include <stdio.h>
#include <string.h>

//#define BUF_SIZE 4096
#define BUF_SIZE 8192
//#define BUF_SIZE 16384

int main(void)
{
    unsigned long long ct = 0;
    size_t written;
    unsigned char *buf;

    buf = malloc(BUF_SIZE);
    memset(buf, 0xFF, BUF_SIZE);

    while (1) {
        written = fwrite(buf, 1, BUF_SIZE, stdout);
        if (written < BUF_SIZE) {
            ct += written;
            break;
        }
        fflush(stdout);
        if (ferror(stdout))
            break;
        ct += written;
    }

    fprintf(stderr, "%llu bytes written\n", ct);

    return 0;
}

设备有 4k 块,还有 68k 或 72k 空闲。我试过缓冲区 4k、8k 和 16k 大小。

这该死的东西 仍然 不起作用。当有 72k 免费的时候,我 使用 8k 缓冲区,它写入 72k,然后认为它写入另一个 4k 并且 补充说。

我想我可以只使用等于块大小的缓冲区大小。 但我什至不确定这是否可靠。

有谁知道如何让它在所有情况下都能正常工作?我想它可能 最好完全绕过缓冲问题并使用 POSIX I/O 相反(openwrite)。


编辑:nsilent22 的建议正确并减少了 循环到两行:

    setbuf(stdout, NULL);
    ...
    while ((written = fwrite(buf, 1, BUF_SIZE, stdout)) > 0)
        ct += written;

I’m thinking it might be best to just bypass the buffering issue entirely and use POSIX I/O instead (open and write).

你有办法!缓冲确实妨碍了你。 fread returns 正确写入流的元素数,但部分流可能尚未刷新,如果设备已满,fflush() 随后可能会失败。没有可移植的方法来找出有多少字节没有被刷新。

您可以 fclose() 文件,重新打开它(以二进制模式)并搜索到最后找出答案,但使用低级别会更简单 Posix I/O首先。

将流缓冲设置为无缓冲应该可行,但如果文件很大,可能会导致性能显着下降。

您确实要写入大量数据以尝试覆盖硬盘。很久以前我写了一个这样的实用程序......绝对使用无缓冲的 strams 并使用低级别 Posix API 和一个大缓冲区,其大小应该是 2 的幂并且你填充随机失败 OS 或可能尝试压缩或以其他方式共享您的数据块的硬件算法。任何伪随机多项式都可以,但一定要在每次写入之间更改缓冲区内容。

请注意,如果您的系统是 32 位,您可能 运行 将文件大小限制为 2G 或 4G。由于使用的文件系统,也可能存在这样的限制。您可以通过创建多个文件来解决这些问题。

考虑使用带有 NULL 参数的 setbuf 函数作为缓冲区。它将关闭流缓冲。