【问题标题】:fgets returning null - file parsingfgets 返回 null - 文件解析
【发布时间】:2020-06-26 21:24:32
【问题描述】:

我正在尝试让一个程序逐行解析文本文件以进行一些数据存储(我尝试过二进制文件存储,但文件中的混合数据类型似乎会搞砸)。

我正在尝试保存 hist[] 中包含的一些条目,它是 history 结构的数组,它基本上包含一个浮点数 (.value) 和一个 time_t (.event_Time)。在保存这些条目之前,应该保存条目的数量(当前是一个 int)。

到目前为止,我可以使用以下函数很好地编写文件:

void data_save(int node_Id, int sensor_Id, history *hist, int entries){
    FILE *file;
    char data_Dir[FILENAME_MAX] = "";
    char directory[FILENAME_MAX] = "";
    char fileName[FILENAME_MAX] = "";
    int length = 0;

    //define path of the file
    _getcwd(data_Dir, FILENAME_MAX);
    strcat(data_Dir, "\\Data");
    strcat(directory,"\\Node_");
    length = snprintf(NULL, 0,"%d",node_Id);
    char str1[length];
    sprintf(str1, "%d", node_Id);
    strcat(directory,str1);
    strcat(fileName,"\\Sensor_");
    length = snprintf(NULL, 0,"%d",sensor_Id);
    char str2[length];
    sprintf(str2, "%d", sensor_Id);
    strcat(fileName,str2);
    strcat(fileName,".txt");

    printf("%s\n", directory);
    printf("%s\n", fileName);

    //check if the Data directory exists, create it if not
    if (directory_exists(data_Dir) == false) {
        printf("Making directory\n");
        _mkdir(data_Dir);
    }
    strcat(data_Dir, directory);

    //check if the Node directory exists, create it if not
    if (directory_exists(data_Dir) == false) {
        printf("Making directory\n");
        _mkdir(data_Dir);
    }
    strcat(data_Dir, fileName);
    printf("%s\n", data_Dir);

    //open the file
    file = fopen(data_Dir, "w");
    if(file == NULL){
        printf("Error while opening file.\n");
        exit (1);
    }

    //Save the number of entries
    printf("Saving %d entries\n", entries);
    fprintf(file, "%d\n", entries);

    //Save each entry in the inverse chronological order
    //(ie. latest event first)
    for(int i=entries-1; i > -1; i--){
        fprintf(file, "%f %ld\n", hist[i].value, hist[i].event_Time);
    }

    fclose(file);

    free(data_Dir);
    free(directory);
    free(fileName);

    printf("Node %d, sensor %d: Data saved Successfully (%d Entries)\n", node_Id, sensor_Id, entries);
    return;
}

但是,我在尝试使用以下函数加载刚刚创建的文件时遇到问题:

history * data_load(int node_Id, int sensor_Id, int *entries){
    FILE *file;
    char data_Dir[FILENAME_MAX] = "";
    char directory[FILENAME_MAX] = "";
    char fileName[FILENAME_MAX] = "";
    int length = 0;
    int entries_Temp;
    int maxChar = 1000;
    char stream[maxChar];

    //define path of the file
    _getcwd(data_Dir, FILENAME_MAX);
    strcat(data_Dir, "\\Data");
    strcat(directory,"\\Node_");
    length = snprintf(NULL, 0,"%d",node_Id);
    char str1[length];
    sprintf(str1, "%d", node_Id);
    strcat(directory,str1);
    strcat(fileName,"\\Sensor_");
    length = snprintf(NULL, 0,"%d",sensor_Id);
    char str2[length];
    sprintf(str2, "%d", sensor_Id);
    strcat(fileName,str2);

    //check if the Data directory exists, exit if not
    if (directory_exists(data_Dir) == false) {
        printf("//Data does not exist\n");
        *entries = 0;
        return NULL;
    }
    strcat(data_Dir, directory);

    //check if the Node directory exists, exit if not
    if (directory_exists(data_Dir) == false) {
        printf("//Data//Node%d does not exist\n", node_Id);
        *entries = 0;
        return NULL;
    }
    strcat(data_Dir, fileName);

    printf("%s\n", data_Dir);

    //check if file exists (ie. there has been no previous
    //data for the given sensor) exit and return 0
    //existing entries
    file = fopen(data_Dir, "r");
    if(file!=NULL){
        printf("No file found for given sensor\n");
        *entries = 0;
        return NULL;
    }

    //Read the number of entries in the file
    printf("Reading number of entries\n");
    printf("%s", fgets(stream, sizeof(stream), file));
    printf("%s\n", stream);
    *entries = strtol(stream, NULL, 10);
    printf("Entries : %d\n", *entries);

    if(*entries > 100){
        printf("Entries is NOK\n");
        exit(1);
    }

    //create the array of structures containing the data
    printf("Creating the data array\n");
    history *hist = malloc(*entries * sizeof(history));

    //Read the data and copy it to the array
    //this has not been tackled yet

    printf("Closing file\n");
    fclose(file);

    printf("Freeing memory (filenames...)\n");
    free(data_Dir);
    free(directory);
    free(fileName);

    printf("Node %d, sensor %d: Data loaded Successfully (%d Entries)", node_Id, sensor_Id, *entries);
    return hist;
}

据我所知,fgets 似乎每次都返回NULL。我不确定文件是否被正确读取,但似乎程序设法打开文件,因为fopen 返回非NULL。我也怀疑我第一次尝试使用二进制文件可能会因为类似的原因而失败,但由于格式的原因,我无法检查在写入或读取文件期间是否发生错误。

我想了解fgets 失败的原因。我也很感激任何有关处理从文件保存和加载数据的更好方法的指导,因为我只是 C 的初学者,而且我很确定有一些更优化的方法可以实现我想要实现的目标。

【问题讨论】:

  • 你检查过文件的内容吗?他们看起来还好吗?
  • minimal reproducible example,强调minmal。您能否使用 较小的 代码段重现错误,然后重新发布,突出显示您看到错误的确切位置?
  • 您应该调用 fgets() 并进行错误/EOF 检查和报告: If ( NULL == fgets(...)){ if( ferror(){ perror( "fegts()" ); return NULL } fprintf( stderr, "fgets() EOF\n" ): return NULL } 如果在 EOF 之前没有换行, fgets() 可以返回一个空字符串,如果在输入中返回一个空行 "\n"。
  • FILENAME_MAX 的价值是多少?
  • @chux-ReinstateMonica,是 260,如果我没记错的话,它包含在 io.h 中

标签: c fgets data-management fileparsing


【解决方案1】:

至少有这些问题:

关闭 1。

对于短缓冲区,sprintf(str1, "%d", node_Id);未定义的行为 (UB),其余代码都是可疑的。

length = snprintf(NULL, 0,"%d",node_Id);
// char str1[length];
char str1[length + 1];
sprintf(str1, "%d", node_Id);

...
//char str2[length];
char str2[length+1];

坏免费

不要在缺少匹配的*alloc() 的情况下调用free()

//free(data_Dir);
//free(directory);
//free(fileName);

建议简化字符串代码。

例如filename

char fileName[FILENAME_MAX];
int length = snprintf(fileName, sizeof fileName, "%s%d%s",
    "\\Sensor_", sensor_Id, ".txt");
if (length < 0 || length >= sizeof fileName) {
  Handle_BufferTooSmall_Error();
}
else {
  printf("%s\n", fileName);
}

【讨论】:

  • 为了健壮性,第一个代码应该检查length &gt; 0,我听说一些snprintf实现在某些情况下失败并返回-1(标准允许)
  • @M.M Err,第一个检查是length &lt; 0。这满足了您的关注和规范的“因此,当且仅当返回值为非负且小于 n 时,以空结尾的输出已被完全写入。”
  • @chux-ReinstateMonica 的“第一个代码”我的意思是您的答案中的第一个代码 sn-p,其中不包含长度检查
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-24
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 2013-10-25
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多