2012-02-09 54 views
35

我一直在为我的CIS类做一个小小的练习,并且非常困惑于C使用从文件中读取的方法。我真正需要做的就是逐行读取文件,并使用从每行收集的信息进行一些操作。我尝试过使用getline方法,其他人没有运气。 我的代码是目前如下:逐行浏览文本文件C

int main(char *argc, char* argv[]){ 
     const char *filename = argv[0]; 
     FILE *file = fopen(filename, "r"); 
     char *line = NULL; 

     while(!feof(file)){ 
     sscanf(line, filename, "%s"); 
     printf("%s\n", line); 
     } 
    return 1; 
} 

现在我正在与sscanf的方法赛格故障,我不知道为什么。我是一个总C诺伯,只是想知道是否有一些我失踪的大图片。 谢谢

+1

此代码甚至不应该编译。 '的sscanf(行,文件名, “%S”);'应该是'的sscanf(线,文件 “%s”);' – Mawg 2016-08-10 14:50:18

+0

注意['虽然'永远是错的(FEOF(文件)!)](HTTP ://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong)。 – 2017-05-08 21:17:11

+0

的可能的复制[C逐行读取文件中的行(https://stackoverflow.com/questions/3501338/c-read-file-line-by-line) – 2017-11-24 16:37:55

回答

93

在这么几行中有这么多问题。我可能会忘记一些:

  • argv [0]是程序名称,而不是第一个参数;
  • 如果你想在一个变量来读,你必须分配内存
  • 一个上FEOF永远循环,一个上的IO功能循环,直到失败,FEOF然后用来确定的失败的原因,
  • sscanf的是有解析一条线,如果要解析的文件,使用的fscanf,
  • “%S”将在第一空间停止作为一个格式?scanf系列
  • 读取线,标准功能是fgets,
  • 返回1从主意味着失败

所以

#include <stdio.h> 

int main(int argc, char* argv[]) 
{ 
    char const* const fileName = argv[1]; /* should check that argc > 1 */ 
    FILE* file = fopen(fileName, "r"); /* should check the result */ 
    char line[256]; 

    while (fgets(line, sizeof(line), file)) { 
     /* note that fgets don't strip the terminating \n, checking its 
      presence would allow to handle lines longer that sizeof(line) */ 
     printf("%s", line); 
    } 
    /* may check feof here to make a difference between eof and io failure -- network 
     timeout for instance */ 

    fclose(file); 

    return 0; 
} 
+19

不要忘了'FCLOSE(文件)'返回之前。 – vivisidea 2014-02-18 09:46:04

+5

了'FCLOSE(文件)'实际上是没有必要的,因为它发生在'main',它会自动关闭所有打开的文件缓冲区。 – Leandros 2015-08-09 13:52:01

+11

@Leandros总是比较安全,而不是抱歉! – Vallentin 2016-07-29 21:26:01

6

要从文件中读取一行,应该使用fgets函数:它从指定文件读取一个字符串,直到换行符或EOF

在你的代码中使用的sscanf不会在所有的工作,你用filename作为格式字符串从line读入一个常量字符串字面%s

SEGV的原因是您写入line指向的未分配内存。

2

除了其他答案外,在最近的C库(符合Posix 2008)中,您可以使用getline。见this answer(涉及相关问题)。

3

假设你正在处理一些其他的分隔符,如\t标签,而不是\n换行符。

的更一般方法的分隔符是使用getc(),其抓住一次一个字符。

注意getc()返回int,这样我们就可以测试与EOF平等。

其次,我们定义char类型的数组line[BUFFER_MAX_LENGTH],为了存储多达在堆栈上BUFFER_MAX_LENGTH-1字符(我们有保存用于\0终止字符的最后一个字符)。

使用数组可避免使用mallocfree在堆上创建正确长度的字符指针。

#define BUFFER_MAX_LENGTH 1024 

int main(int argc, char* argv[]) 
{ 
    FILE *file = NULL; 
    char line[BUFFER_MAX_LENGTH]; 
    int tempChar; 
    unsigned int tempCharIdx = 0U; 

    if (argc == 2) 
     file = fopen(argv[1], "r"); 
    else { 
     fprintf(stderr, "error: wrong number of arguments\n" 
         "usage: %s textfile\n", argv[0]); 
     return EXIT_FAILURE; 
    } 

    if (!file) { 
     fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); 
     return EXIT_FAILURE; 
    } 

    /* get a character from the file pointer */ 
    while(tempChar = fgetc(file)) 
    { 
     /* avoid buffer overflow error */ 
     if (tempCharIdx == BUFFER_MAX_LENGTH) { 
      fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); 
      return EXIT_FAILURE; 
     } 

     /* test character value */ 
     if (tempChar == EOF) { 
      line[tempCharIdx] = '\0'; 
      fprintf(stdout, "%s\n", line); 
      break; 
     } 
     else if (tempChar == '\n') { 
      line[tempCharIdx] = '\0'; 
      tempCharIdx = 0U; 
      fprintf(stdout, "%s\n", line); 
      continue; 
     } 
     else 
      line[tempCharIdx++] = (char)tempChar; 
    } 

    return EXIT_SUCCESS; 
} 

如果你必须使用一个char *,那么你仍然可以使用此代码,但你strdup()line[]阵列,一旦其与线的价值输入的灌满。你必须free此复制串一旦你用它做,否则你会得到一个内存泄漏:

#define BUFFER_MAX_LENGTH 1024 

int main(int argc, char* argv[]) 
{ 
    FILE *file = NULL; 
    char line[BUFFER_MAX_LENGTH]; 
    int tempChar; 
    unsigned int tempCharIdx = 0U; 
    char *dynamicLine = NULL; 

    if (argc == 2) 
     file = fopen(argv[1], "r"); 
    else { 
     fprintf(stderr, "error: wrong number of arguments\n" 
         "usage: %s textfile\n", argv[0]); 
     return EXIT_FAILURE; 
    } 

    if (!file) { 
     fprintf(stderr, "error: could not open textfile: %s\n", argv[1]); 
     return EXIT_FAILURE; 
    } 

    while(tempChar = fgetc(file)) 
    { 
     /* avoid buffer overflow error */ 
     if (tempCharIdx == BUFFER_MAX_LENGTH) { 
      fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n"); 
      return EXIT_FAILURE; 
     } 

     /* test character value */ 
     if (tempChar == EOF) { 
      line[tempCharIdx] = '\0'; 
      dynamicLine = strdup(line); 
      fprintf(stdout, "%s\n", dynamicLine); 
      free(dynamicLine); 
      dynamicLine = NULL; 
      break; 
     } 
     else if (tempChar == '\n') { 
      line[tempCharIdx] = '\0'; 
      tempCharIdx = 0U; 
      dynamicLine = strdup(line); 
      fprintf(stdout, "%s\n", dynamicLine); 
      free(dynamicLine); 
      dynamicLine = NULL; 
      continue; 
     } 
     else 
      line[tempCharIdx++] = (char)tempChar; 
    } 

    return EXIT_SUCCESS; 
} 
+1

之前看到这种“最佳实践”,即使发生蓝色月亮的情况下,我也会对任何'while(!feof(file))'进行倒退投票(注意,可能永远不会是真的,在这种情况下会留下一个循环,“while(true)”也会起作用。)有太多的人认为这是正确的习惯用法。 – AProgrammer 2012-02-09 14:18:18

+0

我不知道这是一个问题。我真的很想更多地了解这一点。这种用法有什么问题? – 2012-02-10 01:38:05

+0

有很多问题出现在这里,例如http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong。 – AProgrammer 2012-02-10 10:22:58