【问题标题】:Reading parameter from file and creating filenames从文件中读取参数并创建文件名
【发布时间】:2020-02-12 15:59:58
【问题描述】:

我想从文件中读取一个名称(例如 config_file.txt,只有一个条目,如 run) 然后用它创建文件名,比如 run0.txt、run1.txt 等等。 但我得到类似 run..0.txt 的东西,带有两个黑点。

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

#define MAXCHAR 1000

void generate(char const *fileName);

int main(int argc, char** argv) {

    generate("config_file.txt");
}

void generate(char const *fileName) {

    char id[MAXCHAR]; 
    FILE *fp;
    char str[MAXCHAR];
    fp = fopen(fileName, "r");
    if (fp == NULL) {
        printf("Could not open file %s", fileName);
        return 1;
    }
    while (fgets(str, MAXCHAR, fp) != NULL) {
            strcpy(id, str);          
    }

    fclose(fp);

    FILE *filePtr;
    char filename[100];
    for(int i = 0;i < 8;i++){
        sprintf(filename, "%s%d.txt", id,i);
        filePtr = fopen(filename, "w");
    }
    fclose(filePtr); 
}

【问题讨论】:

  • 您没有删除fgets() 在读取一行后返回的字符串中保留的换行符。您的fclose(filePtr) 调用也应该在for 循环内。
  • 啊,就是这样,你能告诉我如何解决这个问题吗?
  • 您刚刚检查过您的输入文件吗?确保它没有 run. 我已经运行了你的代码,它按预期工作
  • 切换换行符的可靠方法是str[strcspn(str, "\n")] = '\0';——替代方案必须担心空行和没有换行符等等,但无论如何都有效。如果您认为可能需要处理 CRLF 行结尾,则可以使用 "\n\r",但这通常由 fopen() 为您处理,而不是在打开模式下使用 b。
  • 谢谢你,解决了问题。

标签: c


【解决方案1】:

正如我在 cmets 中所指出的,您的代码不会删除 fgets() 通常保留的换行符,因为它会在尝试向其添加扩展名之前读取行。

换行的简单可靠的方法是:

str[stcspn(str, "\n")] = '\0';

有一些替代方案可能更有效(尽管效率在这里可能是一个红鲱鱼 - 创建文件比读取短行字符需要更长的时间),但您必须正确获得各种条件(空缓冲区, 没有换行符的缓冲区等)。

你还有:

if (fp == NULL) {
    printf("Could not open file %s", fileName);
    return 1;
}
  1. 您应该在 stderr 而不是 stdout 上报告错误。
  2. 您可以考虑包含错误号和/或错误消息。
  3. 您应该用换行符结束消息。
  4. 您不能在返回 void 的函数中写入 return 1; — 编译器必须对此提出抱怨。

C11§6.8.6.4 The return statement:

¶1 带有表达式的 return 语句不应出现在返回类型为 void 的函数中。没有表达式的return 语句只能出现在返回类型为void 的函数中。

因此,你应该考虑写作:

if (fp == NULL)
{
    fprintf(stderr, "Could not open file %s for reading: %s\n", fileName, strerror(errno));
    return;
}

我通常使用自己编写的一组错误报告函数,其中一个告诉库程序的名称(main() 中的err_setarg0(argv[0]);),其他的则根据需要生成错误消息。此代码可在 GitHub 上的 SOQ(堆栈溢出问题)存储库中以文件 stderr.c 和 stderr.h 的形式在 src/libsoq 子目录中找到。

我会写:

if (fp == NULL)
    err_syserr("failed to open file '%s' for reading: ", fileName);

函数不返回。如果我想退货,我会使用err_sysrem()('remark')并安排退货。名称中的sys 部分表示错误号和消息也会自动报告。比起perror(),我更喜欢这些,因为perror() 不容易将程序名称等放入错误消息中。

在某些系统上可以使用类似的库 — macOS 上的 err(3) 和 Linux 上也可用(err(3),工作大致相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-05
    • 2015-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    • 2020-09-27
    • 1970-01-01
    相关资源
    最近更新 更多