代码之家  ›  专栏  ›  技术社区  ›  Navaneeth K N

从文本文件读取所有内容-C

  •  4
  • Navaneeth K N  · 技术社区  · 14 年前

    我正在尝试读取文本文件中的所有内容。这是我写的代码。

    #include <stdio.h>
    #include <stdlib.h>
    
    #define PAGE_SIZE 1024
    
    static char *readcontent(const char *filename)
    {
        char *fcontent = NULL, c;
        int index = 0, pagenum = 1;
        FILE *fp;
        fp = fopen(filename, "r");
    
        if(fp) {
            while((c = getc(fp)) != EOF) {
                if(!fcontent || index == PAGE_SIZE) {
                    fcontent = (char*) realloc(fcontent, PAGE_SIZE * pagenum + 1);
                    ++pagenum;
                }
                fcontent[index++] = c;
            }
            fcontent[index] = '\0';
            fclose(fp);
        }
        return fcontent;
    }
    
    static void freecontent(char *content)
    {
        if(content) {
            free(content);
            content = NULL;
        }
    }
    

    int main(int argc, char **argv)
    {
        char *content;
        content = readcontent("filename.txt");
        printf("File content : %s\n", content);
        fflush(stdout);
        freecontent(content);
        return 0;
    }
    

    由于我是C语言的新手,我想知道这段代码看起来是否完美?你看到什么问题/改进了吗?

    编辑

    fread ftell .

    static char *readcontent(const char *filename)
    {
        char *fcontent = NULL;
        int fsize = 0;
        FILE *fp;
    
        fp = fopen(filename, "r");
        if(fp) {
            fseek(fp, 0, SEEK_END);
            fsize = ftell(fp);
            rewind(fp);
    
            fcontent = (char*) malloc(sizeof(char) * fsize);
            fread(fcontent, 1, fsize, fp);
    
            fclose(fp);
        }
        return fcontent;
    }
    

    6 回复  |  直到 14 年前
        1
  •  10
  •   Martin Ingvar Kofoed Jensen    14 年前

    你应该试着研究一下这些函数 fsize ( 关于fsize,请参阅下面的更新 )以及 fread . 这可能是一个巨大的性能改进。

    使用 获取您正在读取的文件的大小。使用此大小只能分配一次内存( 关于fsize,请参阅下面的更新。获取文件大小并执行一次alloc的想法仍然是一样的 ).

    弗雷德

    long size = fsize(fp);
    fcontent = malloc(size);
    fread(fcontent, 1, size, fp);
    

    更新

    不确定fsize是否跨平台,但可以使用此方法获取文件的大小:

    fseek(fp, 0, SEEK_END); 
    size = ftell(fp);
    fseek(fp, 0, SEEK_SET); 
    
        2
  •  2
  •   Wang    14 年前

    人们经常 realloc

    但更好的是 stat(2)

    还有,为什么你也不呢 fgets(3) 而不是一个字一个字地读,或者,更好的是, mmap(2) 整个东西(或者相关的块,如果它对于内存来说太大)。

        3
  •  2
  •   msw    14 年前

    它可能比以下步骤更慢、更复杂:

    while((c = getc(fp)) != EOF) {
        putchar(c);
    }
    

        4
  •  1
  •   Alok Singhal    14 年前

    这是从一个快速阅读,所以我可能错过了一些问题。

    第一, a = realloc(a, ...); realloc() 失败了,它就回来了 NULL ,但不会释放原始内存。自从你重新分配到 a tmp = realloc(a, ...); if (tmp) a = tmp; 等。

    第二,关于使用 fseek(fp, 0, SEEK_END); stdin ),你就不能回到开头去读了。也, fseek() ftell() 可能无法为二进制文件提供有意义的结果。对于文本文件,它可能无法提供正确的可读取字符数。关于这个话题,有一些有用的信息 comp.lang.c 常见问题 question 19.2

    另外,在原始代码中,不设置 index 当它等于 PAGESIZE ,因此如果文件长度大于 2*PAGESIZE ,将覆盖缓冲区。

    freecontent() 功能:

    static void freecontent(char *content)
    {
        if(content) {
            free(content);
            content = NULL;
        }
    }
    

    是没用的。它只设置 content 无效的 . 就像你写了一个函数 setzero 这样地:

    void setzero(int i) { i = 0; }
    

    一个更好的办法是自己记录下记忆,不要释放任何超出需要的东西。

    您不应该强制转换 malloc() 在C中,从a开始 void * 在C中隐式转换为任何其他对象指针类型。

    希望有帮助。

        5
  •  1
  •   Archie    13 年前

    index 这是非递减的。所以情况 if(!fcontent || index == PAGE_SIZE) 只有一次是真的。所以我觉得支票应该是 index%PAGE_SIZE == 0 index == PAGE_SIZE

        6
  •  0
  •   Jens Gustedt    14 年前

    在POSIX系统(例如linux)上,您可以通过系统调用获得相同的效果 mmap 将所有文件映射到内存中。它有一个映射该文件的选项 ,因此如果更改缓冲区,则会覆盖文件。

    这通常会更有效率,因为您将尽可能多的时间留给系统。不需要这样做 realloc 或者类似的。

    特别是,如果您只是在读取,并且几个进程同时执行该操作,那么整个系统的内存中只有一个副本。