【问题标题】:How to read data from all files in a directory using C Language?如何使用 C 语言从目录中的所有文件中读取数据?
【发布时间】:2015-07-27 17:48:23
【问题描述】:

我正在尝试 1)查找目录中的所有文件并显示它们,2)打开所有找到的文件并从中读取数据(字符) 3)将读取的数据输出到屏幕或新文件。

这是用 C 语言完成的,您将在下面看到我当前的代码。我遇到的问题是:我可以在我的目录中找到所有文件并将它们打印到屏幕上就好了(上面的第 1 点),但是当我尝试打开找到的文件并从中读取数据(字符)时(上面的第 2 点),我遇到了分段错误。

如果我注释掉下面的fscanf(entry_file, "%s", files); 行,但留下entry_file = fopen(in_file->d_name, "r"); 行,它编译正常并将文件写入屏幕。我还尝试使用int i(未在下面显示)索引fscanf 行并产生相同的分段错误。

那么,如何从这些找到的文件中读取数据?谢谢!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>

int main()
{
    DIR* dir;
    FILE *entry_file;
    struct dirent *in_file;
    char files[1000];
    int i;

    dir = opendir("/Users/tcn/data");

    if(dir==NULL){
        printf("Error! Unable to read directory");
        exit(1);
    }

    while( (in_file=readdir(dir)) != NULL) {
        if (!strcmp (in_file->d_name, "."))
            continue;
        if (!strcmp (in_file->d_name, ".."))
            continue;
        printf("%s\n", in_file->d_name);
        entry_file = fopen(in_file->d_name, "r");

        fscanf(entry_file, "%s", files); 
    }

    closedir(dir);
    fclose(entry_file);
    return 0;
}

【问题讨论】:

  • 我不认为这是问题所在,但您应该在循环中关闭您的entry_file
  • entry_file = fopen(in_file-&gt;d_name, "r");需要检查返回值。(可能需要文件的完整路径)还需要fclose每个文件。
  • files 只能容纳1000 字节,也许您的一个或多个文件有更多?此外,您正在打开所有文件而不是关闭它们。您可以同时打开多少个文件是有限制的。另外,检查文件的打开是否成功,如果我没记错的话,in_file-&gt;d_name 只是文件的基本名称,您必须将/Users/tcn/data/ 附加到文件名的开头才能将其传递给fopen() 否则 fopen() 将找不到该文件。您可以使用chdir() 来解决此问题(您只需调用一次)。
  • 您应该在使用之前检查entry_file 是否有NULL,如果不是NULL,则应该在之后检查fclose

标签: c file-io io


【解决方案1】:

看到您在使用 dirin_file 之前正确检查了 NULLin_file,唯一可能导致此问题的其他原因是 entry_file 为空。使用前请检查:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>

int main()
{
    DIR* dir;
    FILE *entry_file;
    struct dirent *in_file;
    char files[1000];
    int i;

    dir = opendir("/Users/tcn/data");

    if(dir==NULL) {
        printf("Error! Unable to read directory");
        exit(1);
    }

    while((in_file=readdir(dir)) != NULL) {
        if (!strcmp (in_file->d_name, "."))
            continue;
        if (!strcmp (in_file->d_name, ".."))
            continue;
        printf("%s\n", in_file->d_name);
        entry_file = fopen(in_file->d_name, "r");
        if (entry_file != NULL) {
            fscanf(entry_file, "%s", files);
            /* whatever you want to do with files */
            fclose(entry_file);
        }
    }

    closedir(dir);
    return 0;
}

另请注意,正如多个其他用户所评论的那样,您应该关闭entry_file循环中。

【讨论】:

    【解决方案2】:

    崩溃的两个最可能的原因是没有检查fopen 的返回值——然后当NULL 尝试使用entry_filefscanffclose 可能会崩溃——以及files 的潜在溢出。

    另一个不会导致崩溃的问题是in_file-&gt;d_name 不包含完整路径,而只包含文件名。因此,如果您正在测试 /Users/tcn/data 中的代码,那么它似乎可以工作,但它会在其他地方失败。要么在文件名前加上/Users/tcn/data/,要么只对当前目录进行操作(.)。

    修复:

    if ((entry_file = fopen(in_file->d_name, "r"))) {
        (void) printf("%s\n", in_file->d_name);
        if (fgets(files, sizeof files, entry_file)) { // or `while`?
            // do something with `files`, it will be overwritten for next file
        }
        (void) fclose(entry_file);
    }
    

    并从代码末尾删除另一个fclose(entry_file)

    另请注意,如果您将此代码用于任意目录,它可能包含管道和/或设备节点,当您尝试读取它们时,它们将永远挂起。

    【讨论】:

    • 为什么(void)printf 之前? (只是好奇)
    • @moffeltje 将未使用的返回值强制转换为(void) 表示它被有意丢弃而不是意外地未分配(printf 也确实返回了一个值,尽管它很少使用)。这是一种我显然已经习惯的编码风格,直到你指出我才意识到我在这里做到了...... =)一些 lints 和编译器选项还可以为未使用的返回值启用警告,以及 (void) 演员表让他们沉默。
    【解决方案3】:

    您将需要一个使用fread() 循环的函数来替换fscanf 行,并执行十六进制转储。一方面,您不知道文件是文本文件还是二进制文件。另一方面,段错误可能来自将不包含newline 的二进制文件读入char files[1000]; 即使文件都是文本文件,您也无法预测您的“慷慨”1000 长度足以容纳第一行文字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-31
      • 2015-07-03
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多