处理文件时的困惑

时间:2017-07-25 02:02:54

标签: c string file format

我编写的程序从一个文件中获取一个字符串,从另一个文件中获取一个字符串,并将它们写入不同列中的第三个文件。我真的有两个问题,如果我使用fgets从文件中获取字符串,它会在行尾停止。是否会自动知道从下一行开始下一个字符串。另外,如何格式化输入以生成两列。一个例子是......

第一个字符串是" John"从第一个文件。 第二个字符串是" Appleseed"来自第二个文件。

第三个文件将在其中"约翰______________________ Appleseed" 第三个文件的第二行有" Benny __________________________ Backburner"

只是格式化列。

2 个答案:

答案 0 :(得分:2)

你想要下划线,还是空间足够?空间更简单。您可以阅读printf()的规范 查看格式字符串的详细信息。

while (fgets(buffer1, sizeof(buffer1), fp1) != 0 &&
       fgets(buffer2, sizeof(buffer2), fp2) != 0)
{
    buffer1[strcspn(buffer1, "\n")] = '\0';
    buffer2[strcspn(buffer2, "\n")] = '\0';
    fprintf(fp3, "%-25s   %s\n", buffer1, buffer2);
}

这将从前两个文件中的每一个中读取一行,从缓冲区中删除换行符,然后使用左对齐的第一列以25的宽度格式化它们,并在第3列空格后打印第二列。

如果你必须使用下划线而不是空格,那么你需要这样的东西:

char uscore[256];
memset(uscore, '_', sizeof(uscore)-1);
uscore[sizeof(uscore)-1] = '\0';

while (fgets(buffer1, sizeof(buffer1), fp1) != 0 &&
       fgets(buffer2, sizeof(buffer2), fp2) != 0)
{
    buffer1[strcspn(buffer1, "\n")] = '\0';
    buffer2[strcspn(buffer2, "\n")] = '\0';
    int len1 = max(0, 25 - strlen(buffer1));
    fprintf(fp3, "%s%*.*s%s\n", buffer1, len1, len1, uscore, buffer2);
}

将它们放在一起,一次说明两种技术:

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

int main(int argc, char **argv)
{
    if (argc != 4)
    {
        fprintf(stderr, "Usage: %s infile-1 infile-2 outfile\n", argv[0]);
        return 1;
    }
    FILE *fp1 = fopen(argv[1], "r");
    FILE *fp2 = fopen(argv[2], "r");
    FILE *fp3 = fopen(argv[3], "w");
    if (fp1 == 0 || fp2 == 0 || fp3 == 0)
    {
        fprintf(stderr, "%s: failed to open one of the files %s, %s or %s\n",
                argv[0], argv[1], argv[2], argv[3]);
        return 1;
    }

    char uscore[256];
    memset(uscore, '_', sizeof(uscore)-1);
    uscore[sizeof(uscore)-1] = '\0';
    char buffer1[1024];
    char buffer2[1024];

    while (fgets(buffer1, sizeof(buffer1), fp1) != 0 &&
           fgets(buffer2, sizeof(buffer2), fp2) != 0)
    {
        buffer1[strcspn(buffer1, "\n")] = '\0';
        buffer2[strcspn(buffer2, "\n")] = '\0';
        fprintf(fp3, "%-25s   %s\n", buffer1, buffer2);

        int len1 = strlen(buffer1);
        if (len1 < 28)
            len1 = 28 - len1;
        else
            len1 = 0;
        fprintf(fp3, "%s%*.*s%s\n", buffer1, len1, len1, uscore, buffer2);
    }
    fclose(fp1);
    fclose(fp2);
    fclose(fp3);
    return 0;
}

示例输入文件data.1

California
Esoteric
Mismatch
Unexpected
Non-sequitur
Extra-long word list from file 1

示例输入文件data.2

Drought
Persecution
Preliminary
Adequate
Pusillanimous
Rather long word from file.2 too

示例输出:

California                  Drought
California__________________Drought
Esoteric                    Persecution
Esoteric____________________Persecution
Mismatch                    Preliminary
Mismatch____________________Preliminary
Unexpected                  Adequate
Unexpected__________________Adequate
Non-sequitur                Pusillanimous
Non-sequitur________________Pusillanimous
Extra-long word list from file 1   Rather long word from file.2 too
Extra-long word list from file 1Rather long word from file.2 too

根据您想要的格式的更精确定义,您可以进行无限的调整。除此之外,您还可以确保“必须具有下划线”示例中的第一个和第二个单词之间至少有3个下划线。您可以限制打印的字符串的长度。

代码应该检查它是否在前1023个字节内获得了换行符;它没有。

答案 1 :(得分:0)

  

如果我使用fgets从文件中获取字符串,它会在行尾停止。它是否会自动知道从下一行开始下一个字符串。

如果该行可以完全存储在缓冲区中,那么是,它将(有关详细说明,请参见下文)。

但是,从文件中读取的数据中并没有像线条那样的东西。它更像是连续的字节流。如果编辑器中有一个文件如下:

a
b
c

fgets看到的数据更像是这个字节流:

a\nb\nc\n

第一次调用fgets会读取a\n,其余输入为

b\nc\n

下一次调用fgets会读取b\n,因此它就像从“下一行”开始一样,但它实际上只是从最后一行继续呼叫停止了。

另请注意,如果线路长于缓冲区会发生什么。如果文件是

abcd
efgh

你做了

fgets(buffer, 3, f)

然后第一次拨打fgets会给ab\0,下一个电话会继续阅读cd\0

换句话说 - 如果行太长而无法完全存储在缓冲区中,fgets从“下一行”继续。如果您总是希望从下一行继续,则必须添加代码才能从文件中读取,直到您阅读\n

  

另外,如何格式化输入以生成两列。

嗯,您的问题没有提供足够的细节来提出确切的代码,例如:什么应该是列之间的间距,如果输入大于间距怎么办,等等。

无论如何 - 请参阅https://stackoverflow.com/a/45295262/4386427(由Jonathan Leffler提供)给你一些好的提示。