【问题标题】:How to read in a file line by line with known format in C如何在C中以已知格式逐行读取文件
【发布时间】:2018-03-10 08:30:54
【问题描述】:

文件格式如下

month day hour:min:sec process: message

例子:

Aug 13 12:20:34 automount[1478]: add_host_addrs: hostname lookup failed

我正在尝试逐行读取,并且对于读取的每一行,确定“消息”是否包含“失败”一词。

我运行时没有输出,请告诉我哪里出错了,谢谢!

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

#define INPUT_SIZE 80

int main()
{
    FILE* file = fopen("logfile", "r");

    char month;
    int day, hour, min, sec;
    char process[INPUT_SIZE];
    char message[INPUT_SIZE];
    char line[INPUT_SIZE];


    if (fgets(line, INPUT_SIZE, file) == NULL)
    {
        perror("Error opening file");
    }
    else
    {
        sscanf("%3s %2d %2d:%2d:%2d %s %s", &month, &day, &hour, &min, &sec, &process, &message);
        printf("%3s %2d %2d:%2d:%2d %s %s\n", month, day, hour, min, sec, process, message);

        while (strstr(message, "fail"))
        {
            /* do something */
        }
    }


    fclose(file);
    if(line == NULL)
    {
        free(line);
    }
    return 0;
}

【问题讨论】:

  • 1) char month; --> char month[4]; 2) sscanf("%3s %2d %2d:%2d:%2d %s %s"... --> sscanf(line, "%3s %2d %2d:%2d:%2d %s %s"...
  • 您对sscanf 的调用完全错误 - 第一个参数是您的输入字符串,然后是格式
  • if(line == NULL) { free(line); } 将被删除。只有 free 事物是动态创建的,例如使用malloc BTW:line 永远不会变为 NULL
  • 3) %s", &amp;month --> %[^\n]", month
  • 为什么在 fgets 失败时会发出有关打开文件的错误消息?如果fopen 失败,请致电perror("logfile")。如果 fgets 失败,也调用perror("logfile") 并期待与打开文件无关的错误消息。

标签: c file input io output


【解决方案1】:

您对sscanf() 的使用不正确。

使用

sscanf(line, "%3s %2d %2d:%2d:%2d %s %[^\n]", month, &day, &hour, &min, &sec, process, message);

其中line 是您正在扫描的字符串。

而不是

sscanf("%3s %2d %2d:%2d:%2d %s %s", &month, &day, &hour, &min, &sec, &process, &message);

请注意,为了读取字符串(使用%s),您使用的是字符数组而不是单个字符。 由于month必须包含多个字符,所以它应该是一个字符数组。

由于数组的名称衰减为它的基地址,所以在提供字符串的地址时不需要&amp; 运算符。
即...%s %s", month, ...process, message)。

输入字符串的message 部分由多个单词组成。通常fscanf() 会在第一个空格或换行符之后停止读取。要继续扫描直到换行,您可以使用%[^\n]。它将读取直到遇到换行符。这样message 将拥有整个hostname lookup failed 而不仅仅是hostname。

现在message 有完整的消息,strstr(message, "fail") 将返回非NULL,控件将进入while 循环。

line 分配在堆栈上而不是堆上。你不应该这样做free(line)。

缓冲区line 的大小将大于其他字符串,这些字符串应该保存通过fgets() 读入line 的部分数据。因此,可能不需要对所有字符串使用相同的大小。

编辑:您可以使用printf() 来输出类似

printf("%s %02d %02d:%02d:%02d %s %s\n", month, day, hour, min, sec, process, message);

%02d 表示如果数字少于 2 位,则在数字前加零,使总位数为 2。

正如Artemy Vysotsky 所评论的那样,可以检查sscanf() 的返回值,以确定是否所有分配都成功。 sscanf() 返回成功分配的数量(或 EOF 输入失败)。在这种情况下,它必须是7。如果没有发生错误。

【讨论】:

  • 谢谢。你知道我怎样才能将输出固定为“00”格式吗?例如,输出看起来像:“Aug 26 3:47:1”,而它应该是“Aug 26 03:47:01”
  • 非常感谢您的帮助!
  • 您应该在使用值之前检查 sscanf 的返回值
  • @ArtemyVysotsky 最后两个字符串的长度未知。应该如何检查返回值?
  • @J...S 你把 scanf 和 printf 搞混了
【解决方案2】:

假设我正在读取包含您要查找的数据的“.csv”文件的第一行,只需执行此操作即可。如果它不是第一行,我想你可以设法解析文件的其余部分,直到你得到“失败”这个词或你想要的任何其他词。

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
  int len = sending();
  char *firstline;
  int i = 0;
  char buf[0];
  int rd ;
  int fd = open("test.csv", O_RDONLY);

  rd = read(fd, buf, 1);    
  firstline = malloc(sizeof(char) * len);
  while (i != len)
    {
      firstline[i] = buf[0];
      i++;
      rd = read(fd, buf, 1);
    }
  firstline[i] = '\0';
  printf("%s\n", firstline);
  int contains = 0;
  i = 0;
  while (firstline[i]) //loop that verifies if it contains the word "fail"
  {
     if (firstline[i] == 'f' && firstline[i + 1] == 'a' && firstline[i + 2] == 'i' && firstline[i + 3] == 'l')
      ++contains;
     i++;
  }
  return (0);
}

int sending()
{
  int fd = open("test.csv", O_RDONLY);
  char buf[1];
  int r = 0;
  r = read(fd, buf, 1);
  int len = 0;

  while (buf[0] != '\n')//reading until '\n' and getting size to malloc
    {
      len++;
      r = read(fd, buf, 1);    
    }
  return len;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 2010-11-19
    • 1970-01-01
    相关资源
    最近更新 更多