CIを使用すると、テキストファイルの内容をすべて読み込んで、n番目の文字列がn番目の文字列テキストファイルの行。ファイルの行は任意に長くすることができます。テキストファイルをCの行の配列に読み込む
これを達成するためのエレガントな方法は何ですか?テキストファイルを1つの適切なサイズのバッファに直接読み込むいくつかの素敵なトリックを知っていますが、それを複数の行に分割すると、(少なくとも私が知る限りは)扱いにくくなります。
ありがとうございました!
CIを使用すると、テキストファイルの内容をすべて読み込んで、n番目の文字列がn番目の文字列テキストファイルの行。ファイルの行は任意に長くすることができます。テキストファイルをCの行の配列に読み込む
これを達成するためのエレガントな方法は何ですか?テキストファイルを1つの適切なサイズのバッファに直接読み込むいくつかの素敵なトリックを知っていますが、それを複数の行に分割すると、(少なくとも私が知る限りは)扱いにくくなります。
ありがとうございました!
これは、テキストを解析し、すべてのEOL(EOLの意味で\ nと\ rを意味する)文字を0に置き換えることを意味します。 このようにして、実際にはバッファを再利用し、別のchar *配列に入れてください(すべて2回だけ行います)。
このようにして、ファイルサイズ全体+ 2回のパーズに対して1つの読み込みを実行すると、パフォーマンスが向上する可能性があります。
Cの場合(C++とは対照的に)、fgets()
を使用している可能性があります。しかし、任意の長さの行のために問題に遭遇する可能性があります。
おそらく、リンクされたリストがこれを行う最もよい方法でしょうか? コンパイラは、どれくらいの大きさにするかわからない配列を持つのが好きではありません。 Linked Listを使用すると、非常に大きなテキストファイルを作成することができ、配列に十分なメモリを割り当てる心配はありません。
残念ながら、私はリンクされたリストを行う方法を学んでいないが、他の人があなたを助けるかもしれない。
任意のサイズは、リンクリストの魅力的な機能ですが、ランダムアクセスを奪い取ることができます。たとえば、最初に行0-4を取得せずに行番号5を取得することはできません。しかし、中間構造としてリンクリストを構築することは良いアイデアです。それで、簡単に配列を構築できます。 –
残念ながら、リンクされたリストは、私が質問から除外したいくつかの詳細のために、この場合はあまり適切ではありません(要するに、ランダムアクセスが必要です)。 もちろん、すべてをリンクリストに読み込んだ後、内容を配列にコピーすることもできますが、私はより洗練されたアプローチを望んでいました。 –
ファイル全体をメモリに読み込むための良い方法があれば、ほとんどの人がそこにいます。完了したら、ファイルを2回スキャンすることができます。一度行を数え、一度行ポインタを設定し、 '\ n'で置き換えます(Windowsのバイナリモードでファイルを読み込む場合は '\ r')。スキャンの間にポインタの配列を割り当てます。これで必要な数が分かりました。
ファイル内の行数を読み取って(ループfgets)、最初の次元が行数+1である2次元配列を作成することができます。次に、ファイルをアレイに再読み込みするだけです。
しかし、要素の長さを定義する必要があります。または、最も長い行サイズをカウントします。
例コード:
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;
}
を使用することができます。行を数えて(正しいサイズの配列を割り当てることができるように)、\ nを0に置き換え、各行の先頭を配列の正しい場所に割り当てます。もちろん、2回のパスでこれを行うことができます。 –
とても良いアイデアです。私はそれに渦をかけるつもりです。 –
+1ファイルからバッファへの最初のコピーを数えずに、 'realloc()'と 'strtok()'を使ってシングルパスを行うことができます。 – pmg