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

时间:2016-02-06 13:36:48

标签: c buffer fwrite

有没有人知道计算实际有多少字节的可靠方法 在磁盘已满的情况下使用C标准I / O(fwrite)编写了吗?

我在使用它时遇到了很多麻烦。问题似乎是 那个fwrite是缓冲的,它有时会认为它已经写好了 比设备实际可以接受的字节数更多。

使用与设备块大小相同的小缓冲区fwrite 报告它已经写了一个完整的缓冲区,当它实际上没有,所以 计数结束比一个块更正确。我修好了 测试错误,如果没有错误,只添加总数。

但是,使用更大的缓冲区,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;

2 个答案:

答案 0 :(得分:1)

  

我认为最好完全绕过缓冲问题并改为使用POSIX I / O(openwrite)。

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

您可以fclose()该文件,重新打开它(以二进制模式)并寻找最终结果,但首先使用低级Posix I / O会更简单。

将流缓冲设置为无缓冲应该可以正常工作,但如果文件很大,可能会导致性能下降。

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

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

答案 1 :(得分:1)

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