在C中将文本文件读入缓冲区的正确方法?

Gar*_*hby 24 c buffer input

我正在处理我希望在处理它们时读入缓冲区的小文本文件,所以我想出了以下代码:

...
char source[1000000];

FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
    while((symbol = getc(fp)) != EOF)
    {
        strcat(source, &symbol);
    }
    fclose(fp);
}
...
Run Code Online (Sandbox Code Playgroud)

这是将文件内容放入缓冲区还是滥用的正确方法strcat()

然后我遍历缓冲区:

for(int x = 0; (c = source[x]) != '\0'; x++)
{
    //Process chars
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ael 70

char source[1000000];

FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
    while((symbol = getc(fp)) != EOF)
    {
        strcat(source, &symbol);
    }
    fclose(fp);
}
Run Code Online (Sandbox Code Playgroud)

这段代码有很多问题:

  1. 它非常慢(您一次提取缓冲区一个字符).
  2. 如果文件大小结束sizeof(source),则容易发生缓冲区溢出.
  3. 真的,当你仔细观察它时,这段代码根本不起作用.如手册页所述:

strcat()函数将以null结尾的字符串s2的副本附加到以null结尾的字符串s1的末尾,然后添加一个终止的"\ 0".

您正在将字符(不是以NUL结尾的字符串!)附加到可能或可能不是NUL终止的字符串.的唯一一次我能想象这个根据手册页描述的工作是,如果该文件中的每个字符是NULL结尾的,在这种情况下,这将是毫无意义.所以,是的,这绝对是一种可怕的滥用strcat().

以下是考虑使用的两种替代方案.

如果您提前知道最大缓冲区大小:

#include <stdio.h>
#define MAXBUFLEN 1000000

char source[MAXBUFLEN + 1];
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
    size_t newLen = fread(source, sizeof(char), MAXBUFLEN, fp);
    if ( ferror( fp ) != 0 ) {
        fputs("Error reading file", stderr);
    } else {
        source[newLen++] = '\0'; /* Just to be safe. */
    }

    fclose(fp);
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您不这样做:

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

char *source = NULL;
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
    /* Go to the end of the file. */
    if (fseek(fp, 0L, SEEK_END) == 0) {
        /* Get the size of the file. */
        long bufsize = ftell(fp);
        if (bufsize == -1) { /* Error */ }

        /* Allocate our buffer to that size. */
        source = malloc(sizeof(char) * (bufsize + 1));

        /* Go back to the start of the file. */
        if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }

        /* Read the entire file into memory. */
        size_t newLen = fread(source, sizeof(char), bufsize, fp);
        if ( ferror( fp ) != 0 ) {
            fputs("Error reading file", stderr);
        } else {
            source[newLen++] = '\0'; /* Just to be safe. */
        }
    }
    fclose(fp);
}

free(source); /* Don't forget to call free() later! */
Run Code Online (Sandbox Code Playgroud)

  • 你可能也希望null终止你的缓冲区.在您的第二个代码示例中,您为null留出了空间,但实际上没有设置它; 在你的第一次,你忽略了留空的空间. (2认同)

tow*_*ele 7

如果您使用的是 Linux 系统,一旦获得文件描述符,您就可以使用 fstat() 获取有关该文件的大量信息

http://linux.die.net/man/2/stat

所以你可能有

#include  <unistd.h> 
void main()
{
    struct stat stat;
    int fd;
    //get file descriptor
    fstat(fd, &stat);
    //the size of the file is now in stat.st_size
}
Run Code Online (Sandbox Code Playgroud)

这可以避免查找文件的开头和结尾。


Mar*_*ett 5

是的-您可能会因对strcat的严重滥用而被捕!

看一下getline(),它一次读取一行数据,但重要的是它可以限制读取的字符数,因此不会溢出缓冲区。

Strcat相对较慢,因为它每次插入字符时都必须搜索整个字符串的结尾。通常,您将保留一个指向字符串存储区当前结尾的指针,并将其传递给getline作为读取下一行的位置。