繁体   English   中英

将文本文件读入 C 中的行数组

[英]Reading text file into an array of lines in C

使用 CI 想要以这样一种方式读入文本文件的内容,即当所有的事情都说完后得到一个字符串数组,其中第 n 个字符串代表文本文件的第 n 行。 文件的行可以任意长。

实现此目的的优雅方式是什么? 我知道一些巧妙的技巧可以将文本文件直接读入一个适当大小的缓冲区,但将其分解成行会使它变得更加棘手(至少据我所知)。

非常感谢!

将其分解为行意味着解析文本并将所有 EOL(EOL 我的意思是 \\n 和 \\r)字符替换为 0。通过这种方式,您实际上可以重用缓冲区并将每行的开头存储到单独的字符中* 数组(全部通过仅执行 2 遍)。

通过这种方式,您可以对整个文件大小+2 次解析进行一次读取,这可能会提高性能。

可以读取文件中的行数(循环 fgets),然后创建一个二维数组,第一维是行数+1。 然后,只需将文件重新读入数组即可。

不过,您需要定义元素的长度。 或者,对最长的行大小进行计数。

示例代码:

inFile = fopen(FILENAME, "r");
lineCount = 0;
while(inputError != EOF) {
    inputError = fscanf(inFile, "%s\n", word);
    lineCount++;
}
fclose(inFile);
  // Above iterates lineCount++ after the EOF to allow for an array
  // that matches the line numbers

char names[lineCount][MAX_LINE];

fopen(FILENAME, "r");
for(i = 1; i < lineCount; i++)
    fscanf(inFile, "%s", names[i]);
fclose(inFile);

你可以用这种方式

#include <stdlib.h> /* exit, malloc, realloc, free */
#include <stdio.h>  /* fopen, fgetc, fputs, fwrite */

struct line_reader {
    /* All members are private. */
    FILE    *f;
    char    *buf;
    size_t   siz;
};

/*
 * Initializes a line reader _lr_ for the stream _f_.
 */
void
lr_init(struct line_reader *lr, FILE *f)
{
    lr->f = f;
    lr->buf = NULL;
    lr->siz = 0;
}

/*
 * Reads the next line. If successful, returns a pointer to the line,
 * and sets *len to the number of characters, at least 1. The result is
 * _not_ a C string; it has no terminating '\0'. The returned pointer
 * remains valid until the next call to next_line() or lr_free() with
 * the same _lr_.
 *
 * next_line() returns NULL at end of file, or if there is an error (on
 * the stream, or with memory allocation).
 */
char *
next_line(struct line_reader *lr, size_t *len)
{
    size_t newsiz;
    int c;
    char *newbuf;

    *len = 0;           /* Start with empty line. */
    for (;;) {
        c = fgetc(lr->f);   /* Read next character. */
        if (ferror(lr->f))
            return NULL;

        if (c == EOF) {
            /*
             * End of file is also end of last line,
        `    * unless this last line would be empty.
             */
            if (*len == 0)
                return NULL;
            else
                return lr->buf;
        } else {
            /* Append c to the buffer. */
            if (*len == lr->siz) {
                /* Need a bigger buffer! */
                newsiz = lr->siz + 4096;
                newbuf = realloc(lr->buf, newsiz);
                if (newbuf == NULL)
                    return NULL;
                lr->buf = newbuf;
                lr->siz = newsiz;
            }
            lr->buf[(*len)++] = c;

            /* '\n' is end of line. */
            if (c == '\n')
                return lr->buf;
        }
    }
}

/*
 * Frees internal memory used by _lr_.
 */
void
lr_free(struct line_reader *lr)
{
    free(lr->buf);
    lr->buf = NULL;
    lr->siz = 0;
}

/*
 * Read a file line by line.
 * http://rosettacode.org/wiki/Read_a_file_line_by_line
 */
int
main()
{
    struct line_reader lr;
    FILE *f;
    size_t len;
    char *line;

    f = fopen("foobar.txt", "r");
    if (f == NULL) {
        perror("foobar.txt");
        exit(1);
    }

    /*
     * This loop reads each line.
     * Remember that line is not a C string.
     * There is no terminating '\0'.
     */
    lr_init(&lr, f);
    while (line = next_line(&lr, &len)) {
        /*
         * Do something with line.
         */
        fputs("LINE: ", stdout);
        fwrite(line, len, 1, stdout);
    }
    if (!feof(f)) {
        perror("next_line");
        exit(1);
    }
    lr_free(&lr);

    return 0;
}

对于 C(与 C++ 相对),您可能最终会使用fgets() 但是,由于任意长度的线,您可能会遇到问题。

也许链表是最好的方法? 编译器不会喜欢有一个不知道它有多大的数组。 使用链表,您可以拥有一个非常大的文本文件,而不必担心为数组分配足够的内存。

不幸的是,我还没有学会如何做链表,但也许其他人可以帮助你。

如果您有一种将整个文件读入内存的好方法,那么您就快完成了。 完成后,您可以扫描文件两次。 一次计算行数,一次设置行指针并将 '\\n' 和(如果在 Windows 二进制模式下读取文件,则可能是 '\\r')替换为 '\\0'。 在扫描之间分配一个指针数组,现在您知道需要多少个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM