【问题标题】:How do I check if file was written to successfully?如何检查文件是否写入成功?
【发布时间】:2020-10-15 19:21:48
【问题描述】:

我已经写了函数,不知道它是否正确但是我如何使用if条件返回true和false?

函数 bool save_book(Book, char)** 输入参数: 指向 Book 的指针和表示文件名的字符串。 返回值:如果图书的内容成功存储到文件中,则返回 true。否则为假。 注意此函数应根据文件名创建或打开一个文件,并在其中存储书籍的每一行。

下面是我的代码

bool save_book(Book *b, char* fileName){

FILE  *filePointer = fopen(fileName,"w");
for (int i = 0; i < pBook->lineCount; i++)
{
    fprintf(filePointer, "%s", b->lines[i]);
}
fclose(filePointer);

return true;
}

这是我正在使用的结构:

typedef struct _Book
{
   int characterCount;
   int lineCount;
   int maxLineCount;
   char **lines;
}Book;
 

【问题讨论】:

  • 阅读C IO functions的文档
  • 检查fopen()是否有效;检查每个fprintf() 是否有效;检查fclose() 是否有效。如果他们都没有报告问题,那么很有可能一切正常。
  • @JonathanLeffler 仍然可以在操作系统上进行缓存,并且当稍后对磁盘的访问失败时,缓存可能会丢失。要保存,需要同步。
  • @12431234123412341234123:是的,并且可以移除磁盘驱动器,而且……这就是为什么机会是“高”而不是“绝对”的原因。如果您使用的是文件流,那么设置相关的同步选项是很麻烦的——在 POSIX 系统上可行,在 Windows 上可能可行。同步安全也有不同级别,对系统性能有不同的影响。不过,尚不清楚描述这些细节是否会使 OP 受益。很大程度上取决于需求是什么,但对于大多数人(程序)来说,大多数时候检查 I/O 操作就足够了——但并不是对所有人都适用。
  • @shardul:在调用fopen 之后验证filePointer != NULL 是最重要的检查。这样可以确保文件已成功打开。 fopen 也有可能成功,fprintf 之后会失败,但这不太可能。因此,根据我的经验,检查fopen 的返回值总是很重要,但通常不需要检查fprintf 的返回值。此外,通常也不需要检查fclose。

标签: c


【解决方案1】:

您必须检查每个单独的 I/O 操作。

为了让它变得有趣,它们都会在出错时返回不同的东西。 fopen 将返回 NULL。 fprintf 将返回一个负数。 fclose 将返回 EOF。

这里附注了每个步骤可能出错的简短列表。

bool save_book(Book *b, char* fileName) {
    // Maybe the directory doesn't exist.
    // Maybe you don't have permission.
    // Maybe there's a disallowed character.
    // Maybe the disk is full.
    // Maybe it's a network drive and there's a network error.
    // Maybe the drive got unmounted.
    FILE  *filePointer = fopen(fileName,"w");
    if( filePointer == NULL ) {
        return false;
    }

    for (int i = 0; i < b->lineCount; i++)
    {
        // Maybe the disk is full.
        // Maybe it's a network drive and there's a network error.
        // Maybe the drive got unmounted.
        if( fprintf(filePointer, "%s", b->lines[i]) < 0 ) {
            // Even though the filePointer variable will be automatically freed
            // the underlying file handle will not be automatically closed.
            // There's a limit to how many open file handles one can have open.
            // No need to check for error, we know something has already gone wrong.
            fclose(filePointer);
            return false;
        }
    }
    // Maybe the disk is full.
    // Maybe it's a network drive and there's a network error.
    // Maybe the drive got unmounted.
    if( fclose(filePointer) != 0 ) {
        return false;
    }

    return true;
}

实际上您可能不需要检查fprintf,检查fclose 应该会发现相同的错误。但是,如果您正在编写一个非常大且成本高昂的文件,您可能想知道您是否迟早会耗尽磁盘空间。

您还可以选择打印错误。这些功能中的每一个都将设置全局errno 失败。您可以使用 strerror 将其转换为人类可读的字符串。

    if( filePointer == NULL ) {
        fprintf(stderr, "Error while opening '%s' for writing: %s", fileName, strerror(errno));
        return false;
    }

请注意,我倾向于检查不是成功的代码,而不是检查确切的错误代码。而不是if( fclose(filePointer) == EOF ),我检查了if( fclose(filePointer) != 0 ),缺少成功代码。这是一种防御性编程实践,以防错误严重到甚至无法返回正确的错误代码(在标准库代码中极不可能)或者我没有完全正确地阅读规范。

【讨论】:

  • @AndreasWenzel 防御性编程验证! :)
  • 谁说是磁盘?在过去,我们将东西存储在录音带上。即使文件成功保存,每次使用它时磁带都会拉伸一点,因此成功保存它的行为可能会使其无法读取。这就是为什么您总是将文件保存在三个不同的物理设备上。不要问我是如何决定三个是最优的......
  • @JerryJeremiah 你有胶带吗?!我写了一个在蜡缸上蚀刻位的设备! ;) 感谢历史记录。我最接近磁带的是datasettes。
  • 是的。我说的是数据集,但我使用的是 Apple ][ 所以你必须为耳机和麦克风插孔提供自己的盒式录音机。
  • 对于任何年龄不足以记住录音带的未来读者 - 这是一个蜡缸:nfsa.gov.au/collection/curated/wax-cylinder-recordings
猜你喜欢
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2023-03-25
  • 2019-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多