簡體   English   中英

從文本文件中讀取所有內容 - C.

[英]Reading all content from a text file - C

我試圖從文本文件中讀取所有內容。 這是我寫的代碼。

#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的新手,我想知道這段代碼是否完美無缺? 你看到有什么問題/改進嗎?

使用的編譯器:GCC。 但是這段代碼有望跨平台。

任何幫助,將不勝感激。

編輯

這是帶有freadftell的更新代碼。

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;
}

我想知道這個函數的相對復雜性是什么?

您應該嘗試查看函數fsize關於fsize,請參閱下面的更新 )和fread 這可能會帶來巨大的性能提升。

使用fsize獲取您正在閱讀的文件的大小。 使用此大小僅執行一次內存分配。 關於fsize,請參閱下面的更新。獲取文件大小和執行一個alloc的想法仍然相同 )。

使用fread來阻止讀取文件。 這比單個charecter讀取文件要快得多。

像這樣的東西:

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); 

人們常常realloc兩倍現有大小來獲得固定的時間里,而不是線性的。 這使緩沖區的大小不超過兩倍,這通常是可以的,並且您可以選擇在完成后重新分配回正確的大小。

但更好的是stat(2)表示文件大小並分配一次(如果文件大小不穩定則有一些額外的空間)。

另外,為什么你不是fgets(3)而不是逐個字符讀取,或者更好的是, mmap(2)整個事物(或者相關的塊,如果它對於內存來說太大)。

它可能比以下更慢,更復雜:

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

它與您的代碼完全相同。

這是一個快速閱讀,所以我可能錯過了一些問題。

首先, a = realloc(a, ...); 是錯的。 如果realloc()失敗,則返回NULL ,但不釋放原始內存。 由於您重新分配給a ,原始內存丟失(即,它是內存泄漏)。 正確的方法是: tmp = realloc(a, ...); if (tmp) a = tmp; tmp = realloc(a, ...); if (tmp) a = tmp; 等等

第二,關於使用fseek(fp, 0, SEEK_END);確定文件大小fseek(fp, 0, SEEK_END); ,請注意,這可能會也可能不會奏效。 如果文件不是隨機訪問(例如stdin ),您將無法返回到開頭讀取它。 此外, fseek()后跟ftell()可能無法為二進制文件提供有意義的結果。 對於文本文件,它可能無法為您提供可讀取的正確數量的字符。 comp.lang.c上有關於此主題的一些有用信息。常見問題19.2

此外,在原始代碼中,當它等於PAGESIZE ,不將index設置為0,因此如果文件長度大於2*PAGESIZE ,則將覆蓋緩沖區。

你的freecontent()函數:

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

沒用。 它只將content副本設置為NULL 就像你寫了一個像這樣的函數setzero

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

一個更好的想法是自己跟蹤記憶,而不是釋放任何比需要更多或更少的東西。

你不應該在C中強制轉換malloc()realloc()的返回值,因為void *被隱式轉換為C中的任何其他對象指針類型。

希望有所幫助。

我在這里可以看到的一個問題是變量index ,它是非遞減的。 所以條件if(!fcontent || index == PAGE_SIZE)只會為真一次。 所以我認為檢查應該像index%PAGE_SIZE == 0而不是index == PAGE_SIZE

在POSIX系統(例如linux)上,您可以使用系統調用mmap獲得相同的效果,該系統調用mmap將所有文件映射到內存中。 它有一個選項可以在寫入時映射該文件副本 ,因此如果更改緩沖區,則會覆蓋文件。

這通常會更有效率,因為您盡可能多地留在系統中。 不需要realloc或類似的。

特別是,如果您只是在閱讀並且多個進程同時執行此操作,則整個系統的內存中只有一個副本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM