【问题标题】:File interleaving, file scanning, file printing文件交错、文件扫描、文件打印
【发布时间】:2014-05-17 06:21:57
【问题描述】:

编写一个程序,从 命令行:week09_1 file1.txt file2.txt file3.txt

您的程序应打开文件 file1.txt 和 file2.txt 以供读取和创建
文件file3.txt如下:

file3.txt的第一行是file1.txt的第一行
file3.txt 的第二行是 file2.txt 的第一行
file3.txt的第三行是file1.txt的第二行
file3.txt的第四行就是file2.txt的第二行

... 当一个输入文件到达 EOF 时,另一个文件中的剩余行
应该被复制到输出文件并且程序终止。你的
如果文件名少于 3 个,程序应打印相应的错误消息
在命令行上提供,或者如果文件无法打开。

所以到目前为止,我已经能够做提示要求我做的事情;但是,当一个文件用完打印行然后它只从另一个文件打印时打印在同一行,我想知道当它只从一个文件打印时如何让它开始一个新行。

我也不明白我应该如何按照提示询问的方式在命令行参数中实现。

#include <stdio.h>
char line1[256] = { };
char line2[256] = { };
char check;
int END = 0, END1 = 0, END2 = 0;

int main(int argc, char *argv[]) {
  if (argc != 4) {
    printf("Error: Wrong amount of arguments\n");
    return 0;
  }
  FILE *file1 = fopen("argv[1]", "r");
  FILE *file2 = fopen("argv[2]", "r");
  FILE *file3 = fopen("argv[3]", "w");
  if (argv == NULL) {
    printf("Error: file could not be opened.\n");
    return 0;
  }

  while (END != 2) {
    check = fgets(line1, 256, file1);
    if (check != NULL) {
      fprintf(file3, "%s", line1);
    } else if (check == NULL) {
      END1 = 1;
    }

    check = fgets(line2, 256, file2);
    if (check != NULL) {
      fprintf(file3, "%s", line2);
    } else if (check == NULL) {
      END2 = 1;
    }
    END = END1 + END2;
  }
  return 0;
}

【问题讨论】:

  • 请注意行可能会很长。
  • 在缩进代码时:删除幻数(例如 256),将“全局”变量(实际上是文件范围)移动到 main(),检查 fopen() 的返回值,然后fclose() 处理完您的文件。
  • 命令行参数将在argv[1]argv[2]argv[3]中(如果它们在那里);在这种情况下,argc 将是 4。您应该(至少)验证已经给出了多少个参数,如果 argc 不完全是 4,则使用使用消息退出。
  • 输入行有多长?如果某些输入行超过 256 个字符,则代码必须处理被fgets 截断的行。要么,要么你需要使用更大的行缓冲区。
  • 现在你的代码更糟了(char line[] = {}; 等)——我不确定它是否可以编译。 256有点小,但也不是不合理。您可以使用 4096 并忽略该问题,或者使用 POSIX getline() 并且在大多数情况下不必担心行长。

标签: c linux file


【解决方案1】:

我会带你去那里的。

鉴于此文件为file1.txt

File 1, Line 1
File 1, Line 2
File 1, Line 3
File 1, Line 4
File 1, Line 5
File 1, Line 6
File 1, Line 7
File 1, Line 8

这个文件是file2.txt:

File 2, Line 1
File 2, Line 2
File 2, Line 3
File 2, Line 4
File 2, Line 5
File 2, Line 6
File 2, Line 7
File 2, Line 8
File 2, Line 9
File 2, Line 10

您可以像这样阅读它们并以交错方式将它们打印出来:

#include <stdio.h>

int main(int argc, char *argv[]){
    char buffer[4096];
    char *ptr;
    int i=0;

    FILE *file1 = fopen("/tmp/file1.txt", "r");
    FILE *file2 = fopen("/tmp/file2.txt", "r");

    // while there is something from either file, do...
    while (!feof(file1) || !feof(file2)){
            // use modulo to switch file1, file2, etc
        if (i%2 == 0) {
            ptr=fgets(buffer, sizeof(buffer), file1);
        }   
        else {
            ptr=fgets(buffer, sizeof(buffer), file2);
        }
            // test if the last fgets actually read something by testing ptr vs NULL
        if (ptr)
            printf("%s", buffer);
        ++i;
    }   
    return 0;
}

打印:

File 1, Line 1
File 2, Line 1
File 1, Line 2
File 2, Line 2
File 1, Line 3
File 2, Line 3
File 1, Line 4
File 2, Line 4
File 1, Line 5
File 2, Line 5
File 1, Line 6
File 2, Line 6
File 1, Line 7
File 2, Line 7
File 1, Line 8
File 2, Line 8
File 2, Line 9
File 2, Line 10 

您需要将打印添加到 file3、文件上的适当 fclose、读取 argv 和适当的错误测试/反应。

【讨论】:

  • 你能给我解释一下while循环中的!feof
  • 它说'当系统没有在两个输入流之一上检测到 EOF 时,做......'。我对while (!feof(fp)) 循环不太满意,但它在这段代码中被安全地使用了。
  • 嗯,我不太了解代码的 feof 部分,我的代码似乎可以工作,但只是在一个文件到达 EOF 后,它不会开始新行,所以当下一行的第一行时文件开始打印它不是在新行中打印。我需要一些帮助。
  • @JonathanLeffler:It says 'while the system has not detected EOF on one of the two input streams, do ...'. 它实际上是说'虽然系统没有在两个输入流上检测到 EOF,但执行...',因为它是一个逻辑或。
  • @dawg:是的,你说得对。当时我有点分心(工作,或者类似的事情)。
【解决方案2】:

我觉得代码比较好管理,尤其是文件最后一行没有换行的情况下,如果用函数处理一个文件的一行,反复调用的话。

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

static int read_and_print_line(FILE *ifp, FILE *ofp)
{
  char buffer[64];
  int eol_needed = 0;
  while (fgets(buffer, sizeof(buffer), ifp) != 0)
  {
    fputs(buffer, ofp);
    if (strchr(buffer, '\n') != 0)
      return 0;
    /* Either more to read in current line or EOF without newline */
    eol_needed = 1;
  }
  if (eol_needed)
    putc('\n', ofp);
  return EOF;
}

int main(int argc, char **argv)
{
  if (argc != 4)
  {
    fprintf(stderr, "Usage: %s in-file1 in-file2 outfile\n", argv[0]);
    return 1;
  }
  FILE *if1 = fopen(argv[1], "r");
  FILE *if2 = fopen(argv[2], "r");
  FILE *ofp = fopen(argv[3], "w");
  if (if1 == 0)
    fprintf(stderr, "Failed to open %s for reading\n", argv[1]);
  if (if2 == 0)
    fprintf(stderr, "Failed to open %s for reading\n", argv[2]);
  if (ofp == 0)
    fprintf(stderr, "Failed to open %s for reading\n", argv[3]);
  if (if1 == 0 || if2 == 0 || ofp == 0)
    return 1;
  int r1 = 0;
  int r2 = 0;
  while ((r1 = read_and_print_line(if1, ofp)) != EOF &&
         (r2 = read_and_print_line(if2, ofp)) != EOF)
    ;

  assert(r1 == EOF || r2 == EOF);
  assert(r1 != r2);

  while (read_and_print_line(if1, ofp) != EOF)
    ;
  while (read_and_print_line(if2, ofp) != EOF)
    ;

  fclose(if1);
  fclose(if2);
  fclose(ofp);
  return 0;
}

我很满意这适用于它自己的源代码,也适用于末尾没有换行符的一个“行”文件 (echo -n Gobbledygook &gt;file1),依此类推。缓冲区显示为 64 字节以帮助测试(如果您愿意,可以将其减少到 32 甚至更低)。经过测试,我会编译成 4096 这样的大小。

【讨论】:

  • +1 就像两者的 while 循环,然后每个循环分别结束。建议int r2 = 0 以防止assert() 出现问题,如果r1 立即为EOF,因为r2 从未设置过。
  • 如果没有'\n',我会再次 +1 以谨慎处理长行和 EOF。
【解决方案3】:

一些 UB - 代码需要修复

//char check;
void * check;

建议:

char line1[256] = { 0 };
char line2[256] = { 0 };

更改错误检查。可以扩展哪个文件是坏的

if (file1 == NULL || file2 == NULL || file3 == NULL) {
  printf("Error: file could not be opened.\n");
  return 0;
}

但其他人有一个很好的“其余答案”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-13
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    相关资源
    最近更新 更多