2016-09-05 2 views
0

大きなファイルを読みたいのですが、行の最初の文字が ""ではないのですが。 しかし、私が書いたコードは非常に遅いです。どのようにルーチンをスピードアップできますか? getlineではなく、より良い解決策がありますか?Cが大きなファイルをchar *配列に読み込むのが遅すぎる

void readString(const char *fn) 
{ 
    FILE *fp; 
    char *vString; 
    struct stat fdstat; 
    int stat_res; 

    stat_res = stat(fn, &fdstat); 
    fp = fopen(fn, "r+b"); 

    if (fp && !stat_res) 
    { 
     vString = (char *)calloc(fdstat.st_size + 1, sizeof(char)); 

     int dataEnd = 1; 
     size_t len = 0; 
     int emptyLine = 1; 
     char **linePtr = malloc(sizeof(char*)); 
     *linePtr = NULL; 

     while(dataEnd) 
     { 
     // Check every line 
     getline(linePtr, &len, fp); 

     // When data ends, the line begins with space (" ") 
     if(*linePtr[0] == 0x20) 
      emptyLine = 0;   

     // If line begins with space, stop writing 
     if(emptyLine) 
      strcat(vString, *linePtr); 
     else 
      dataEnd = 0; 
     } 

     strcat(vString, "\0"); 
     free(linePtr); 
     linePtr = NULL; 
    } 
} 

int main(int argc, char **argv){ 
    readString(argv[1]); 
    return EXIT_SUCCESS; 
} 
+0

'calloc' =' malloc' + memset(...、0、...) 'を一歩にします。 –

+0

そして 'malloc(0)'は 'size_t'のために有効なアドレスを返しません、[getline](http://man7.org/linux/man-pages/man3 /getline.3.html)マニュアル: 'size_t len = 0;' ... 'getline(&len、&len、stream)' –

+0

Thx!私はそれを修正しましたが、これは私のコードをスピードアップしませんでした;) –

答えて

3

がどのようにルーチンをスピードアップすることができますような何か?

プログラムで最も疑わしい点は、パフォーマンスの面ではstrcat()です。それぞれの呼び出しで、ソースストリングを追加する場所を見つけるために、最初から宛先ストリング全体をスキャンする必要があります。その結果、ファイルの行の長さが定数(大きなものでも)で制限されている場合、アプローチのパフォーマンスはファイルの長さの2乗に比例します。

漸近的な複雑さの分析は、必ずしも全話を伝えるわけではありません。コードのI/O部分はファイルの長さに応じて線形に拡張されます.I/Oはメモリ内のデータ操作よりもはるかに高価であるため、ファイルが十分小さい場合はパフォーマンスが支配的になります。あなたがその政権にいるなら、あなたはすでにあなたがしているよりもはるかに良くするつもりはないでしょう。その場合には、しかし、あなたはまだfread()を経由して、一度にファイル全体を読み込み、その後、strstr()を介してエンド・オブ・データのためにそれをスキャンすることによって、より良いビット行う可能性があります:

size_t nread = fread(vString, 1, fdstat.st_size, fp); 

// Handle nread != fdstat.st_size ... 

// terminate the buffer as a string 
vString[nread] = '\0'; 

// truncate the string after the end-of-data: 
char *eod = strstr(vString, "\n "); 
if (eod) { 
    // terminator found - truncate the string after the newline 
    eod[1] = '\0'; 
} // else no terminator found 

直線的に比例するので、それはアドレスあなたの漸近的な複雑さの問題もありますが、関心のあるデータがファイルよりもずっと短くなる場合は、必要以上に高価なI/Oを行うケースにあなたを残します。その場合、@ laissez_faireが示唆しているように、1つの方法はチャンクで読み込むことです。もう1つは、元のアルゴリズムを調整してvStringの末尾を追跡し、strcat()の代わりにstrcpy()を使用して、それぞれの新しい行を追加することです。

  • あなたはあなただけだとして、当初、*vStringに割り当てられたメモリをゼロ埋めする必要がないことに注意し、さらに

    char *linePtr = NULL; 
    size_t nread = 0; 
    size_t len = 0; 
    
    *vString = '\0'; // In case the first line is end-of-data 
    for (char *end = vString; ; end += nread) { 
        // Check every line 
        nread = getline(&linePtr, &len, fp); 
    
        if (nread < 0) { 
         // handle eof or error ... 
        } 
    
        // When data ends, the line begins with space (" ") 
        if (*linePtr == ' ') { 
         break; 
        } 
        strcpy(end, *linePtr); 
    } 
    
    free(linePtr); 
    

    :そのバージョンの重要な部分は、次のようになりますこれらのゼロを実際のデータで上書きします(そしてバッファの残りの部分を無視します)。

  • calloc()を含むmalloc()ファミリ関数の戻り値をキャストしないでください。

0

は、あなたが関数freadを使用してファイルを読み込み、各ステップでデータの大きなチャンクを読んで、それを読んだ後、データを解析しようとしたことがありますか?

#include <stdio.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <stdlib.h> 

char *readString(const char *fn) 
{ 
    FILE *fp; 
    char *vString; 
    struct stat fdstat; 
    int stat_res; 

    stat_res = stat(fn, &fdstat); 
    fp = fopen(fn, "r+b"); 

    if (fp && !stat_res) { 
    vString = (char *) calloc(fdstat.st_size + 1, sizeof(char)); 

    int newline = 1; 
    int index = 0; 
    while (index < fdstat.st_size) { 
     int len = 
     fdstat.st_size - index > 
     4096 ? 4096 : fdstat.st_size - index; 
     char *buffer = (char *) malloc(len); 
     int read_len = fread(buffer, 1, len, fp); 
     int i; 
     if (newline) { 
     if (read_len > 0 && buffer[0] == ' ') { 
      return vString; 
     } 
     newline = 0; 
     } 
     for (i = 0; i < read_len; ++i) { 
     if (buffer[i] == '\n') { 
      if (i + 1 < read_len && buffer[i + 1] == ' ') { 
      memcpy(vString + index, buffer, i + 1); 
      return vString; 
      } 
      newline = 1; 
     } 
     } 
     memcpy(vString + index, buffer, read_len); 
     index += read_len; 
    } 
    } 
    return vString; 
} 

int main(int argc, char **argv) 
{ 
    char *str = readString(argv[1]); 
    printf("%s", str); 
    free(str); 
    return EXIT_SUCCESS; 
} 
関連する問題