搜索文件中的元素并打印整行

时间:2019-03-19 09:55:41

标签: c file

我有一个包含以下内容的文件:

Code                Name     Income    Allow      Pens     Ins    Depend    Charity    Taxable       Tax       Net
------------------------------------------------------------------------------------------------------------------------
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
 001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275

如果输入的代码与文件中的代码相同,我想打印一条记录。
这是我的代码:

fscanf(fp, " %3d%s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t);  
printf("\n");
printf(" 03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
                `

但不起作用。
因此,我正在考虑使用fscanf来读取代码,然后打印包含该代码的行。但是,如何在没有其他内容(例如NameIncome,...)的情况下读取代码,以及如何读取代码的前导0呢?

2 个答案:

答案 0 :(得分:1)

首先,您不能使用您提供的 scanf 读取文件的标题,因为 Code 与第一个%d不兼容,因此您需要绕过前2行

在您的 printf 中缺少警告%来打印代码,因此%s将该代码视为字符串,但行为没有指定(通常是崩溃)

  

但是我如何在没有名称,收入等其他内容的情况下读取代码

当然,如果您使用您的 scanf ,还要阅读其他字段,这是一个真正的问题吗?您还可以将每行读为字符串( fgets getline ),并查看开头是否有所需的代码,在这种情况下,可以管理其余的字符串提取所需的字段等

如果文件内容的格式很严格,另一种方法是使用 fseek 更改文件指针,使其仅读取符合预期的代码(请参见答案末尾的建议) )。

  

如何读取代码中是否以0开头?

我不理解 scanf 读得很好,这不是八进制的,因为有008。如果左侧的0很重要,请不要将代码作为数字来管理,在文件中以及提供搜索代码时都输入字符串


您的代码很好地阅读了您的输入文件:

#include <stdio.h>

int bypassLine(FILE * fp)
{
  int c;

  for (;;) {
    c = fgetc(fp);

    if (c == EOF)
      return 0;
    if (c == '\n')
      return 1;
  }
}

int main()
{
  FILE * fp = stdin;
  int code_t;
  char buffer[64];
  double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;

  if (!bypassLine(fp) || !bypassLine(fp))
    puts("too short file");
  else {
    while (fscanf(fp, " %3d%s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 11) {
      printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
    }
  }
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ cat f
Code                Name     Income    Allow      Pens     Ins    Depend    Charity    Taxable       Tax       Net
------------------------------------------------------------------------------------------------------------------------
008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ ./a.out < f
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
 001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ 

请注意,仅使用%s来读取 scanf 中的字符串时,就无法防止溢出,如果最好使用%63s,因为我调整了 buffer < / em> 64


稍作更改即可搜索代码,仍然使用您的 scanf ,并在参数中提供文件名和所需的代码:

#include <stdio.h>

int bypassLine(FILE * fp)
{
  int c;

  for (;;) {
    c = fgetc(fp);

    if (c == EOF)
      return 0;
    if (c == '\n')
      return 1;
  }
}

int main(int argc, char ** argv)
{
  if (argc != 3)
    printf("usage : %s <file> <code>\n", *argv);
  else {
    FILE * fp;
    int code_t, expected;
    char buffer[64];
    double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;

    if ((fp = fopen(argv[1], "r")) == NULL) {
      fprintf(stderr, "cannot open '%f'\n", argv[1]);
      return -1;
    }

    if (!bypassLine(fp) || !bypassLine(fp)) {
      fprintf(stderr, "too short file '%s'\n", argv[1]);
      fclose(fp);
      return -1;
    }

    if (sscanf(argv[2], "%d%c", &expected, buffer) != 1) {
      fprintf(stderr, "invalid code '%s'\n", argv[2]);
    }
    else {
      while (fscanf(fp, " %3d%63s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 11) {
        if (code_t == expected) {
          printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
          fclose(fp);
          return 0;
        }
      }
      fprintf(stderr, "code %d not found in '%s'\n", expected, argv[1]);
    }
    fclose(fp);
    return -1;
  }
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ ./a.out ./f 2
code 2 not found in './f'
pi@raspberrypi:/tmp $ ./a.out ./f 8
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
pi@raspberrypi:/tmp $ 

使用 fseek 在文件中的代码之间直接移动的另一种方式:

#include <stdio.h>

int bypassLine(FILE * fp)
{
  int c;

  for (;;) {
    c = fgetc(fp);

    if (c == EOF)
      return 0;
    if (c == '\n')
      return 1;
  }
}

int main(int argc, char ** argv)
{
  if (argc != 3)
    printf("usage : %s <file> <code>\n", *argv);
  else {
    FILE * fp;
    int code_t, expected;
    char buffer[64];
    double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;

    if ((fp = fopen(argv[1], "r")) == NULL) {
      fprintf(stderr, "cannot open '%f'\n", argv[1]);
      return -1;
    }

    if (!bypassLine(fp) || !bypassLine(fp)) {
      fprintf(stderr, "too short file '%s'\n", argv[1]);
      fclose(fp);
      return -1;
    }

    if (sscanf(argv[2], "%d%c", &expected, buffer) != 1) {
      fprintf(stderr, "invalid code '%s'\n", argv[2]);
    }
    else {
      long offset = ftell(fp);

      while (fscanf(fp, " %03d", &code_t) == 1) {
        if (code_t == expected) {
          /* extract the other fields */
          if (fscanf(fp, "%63s%lf%lf%lf%lf%lf%lf%lf%lf%lf", buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 10) {
            printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
            fclose(fp);
            return 0;
          }
          else {
            fprintf(stderr, "code %d found but cannot read next fields\n", code_t);
            fclose(fp);
            return -1;
          }
        }
        /* the lines are supposed having all the times 114 characters newline included */
        offset += 114;
        if (fseek(fp, offset, SEEK_SET) == -1) {
          fprintf(stderr, "error when going at offset %d of '%s'\n", offset, argv[1]);
          fclose(fp);
          return -1;
        }
      }
      fprintf(stderr, "code %d not found in '%s'\n", expected, argv[1]);
    }
    fclose(fp);
    return -1;
  }
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ cat f
Code                Name     Income    Allow      Pens     Ins    Depend    Charity    Taxable       Tax       Net
------------------------------------------------------------------------------------------------------------------------
008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ ./a.out ./f 8
 008                John     100000     4000      5000    1000      3200       1000      85800     20280     79720
pi@raspberrypi:/tmp $ ./a.out ./f 1
 001                 Doe      50000     4000         0     500      1600          0      43900      7725     42275
pi@raspberrypi:/tmp $ ./a.out ./f 11
code 11 not found in './f'

答案 1 :(得分:0)

  

如果输入的代码与文件中的代码相同,我想打印一条记录。

如果您的目标只是打印“代码”与用户提供的某些值匹配的记录(又称行),则您的方法似乎过于复杂,因为无需扫描所有字段。

只需使用fgets来读取行,然后检查Code值并进行打印(如果匹配)。

类似的东西:

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


int main(int argc, char* argv[]){
  if (argc != 2)
  {
    printf("Wrong usage...\n");
    return 1;
  }
  int code_to_print = atoi(argv[1]);
  int code_read;

  FILE* fp = fopen("db.txt", "r");
  if (!fp)
  {
    printf("File error...\n");
    return 1;
  }
  char buf[1024];

  while (fgets(buf, sizeof buf, fp))
  {
    if (sscanf(buf, "%d", &code_read) == 1 && code_read == code_to_print)
    {
      printf("%s", buf);
    }
  }
  fclose(fp);
}

使用如下程序:

./prog 8
  

..如何读取代码是否以0开头?

如果前导零很重要,则您无法使用%d进行扫描,因为这将“删除”零。相反,您需要将代码作为单词进行扫描。喜欢:

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


int main(int argc, char* argv[]){
  if (argc != 2)
  {
    printf("Wrong usage...\n");
    return 1;
  }

  char code_read[4] = {0};

  FILE* fp = fopen("db.txt", "r");
  char buf[1024];

  while (fgets(buf, sizeof buf, fp))
  {
    if (sscanf(buf, "%3s", code_read) == 1 && strcmp(code_read, argv[1]) == 0)
    {
      printf("%s", buf);
    }
  }
  fclose(fp);
}

使用如下程序:

./prog 008