Cでは、テキストファイルを読み取ってすべての文字列を印刷するにはどうすればよいですか


94

名前の付いたテキストファイルがあります test.txt

このファイルを読み取ってコンテンツをコンソールに出力できるCプログラムを作成したいと思います(ファイルにASCIIテキストのみが含まれていると想定します)。

文字列変数のサイズを取得する方法がわかりません。このような:

char str[999];
FILE * file;
file = fopen( "test.txt" , "r");
if (file) {
    while (fscanf(file, "%s", str)!=EOF)
        printf("%s",str);
    fclose(file);
}

999によって返される文字列fscanfがそれより大きくなる可能性があるため、サイズは機能しません。どうすればこれを解決できますか?

回答:


134

最も簡単な方法は、文字を読み取り、読み取った直後に印刷することです。

int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
    while ((c = getc(file)) != EOF)
        putchar(c);
    fclose(file);
}

cは負の数intであるため、は上にEOFあり、プレーンcharunsigned

ファイルをチャンクで読み取りたいが、動的メモリ割り当てがない場合は、次のことができます。

#define CHUNK 1024 /* read 1024 bytes at a time */
char buf[CHUNK];
FILE *file;
size_t nread;

file = fopen("test.txt", "r");
if (file) {
    while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
        fwrite(buf, 1, nread, stdout);
    if (ferror(file)) {
        /* deal with error */
    }
    fclose(file);
}

上記の2番目の方法は、基本的に、動的に割り当てられた配列を使用してファイルを読み取る方法です。

char *buf = malloc(chunk);

if (buf == NULL) {
    /* deal with malloc() failure */
}

/* otherwise do this.  Note 'chunk' instead of 'sizeof buf' */
while ((nread = fread(buf, 1, chunk, file)) > 0) {
    /* as above */
}

fscanf()with %sas formatのメソッドは、ファイル内の空白に関する情報を失うため、ファイルをに正確にコピーしているわけではありませんstdout


そのファイルをc / c ++で開かなくてもファイルからデータを読み取ることは可能ですか?
Sagar Patel 2015年

テキストファイルにコンマ区切りの整数値が含まれている場合はどうなりますか?コードが何であるかよりも、その中にあなたの答えを編集することができます。
モーシン2016年

上記は、あらゆる種類のテキストファイルで機能します。CSVファイルから数値を解析する場合、それは別の問題です。
Alok Singhal 2016年

1
@overexchange質問は行についてではなく、ファイルを読み取ってその内容をにコピーすることについてstdoutです。
Alok Singhal 2017年

1
@shjeffファイルにEOF文字を含めることはできません。cはintであり、CはそれEOFが有効な文字と等しくないことを保証することに注意してください。
Alok Singhal 2017年

60

チャンクで読み取ることについては、ここに多くの良い答えがあります。すべてのコンテンツを一度にバッファーに読み取って出力する小さなトリックを紹介します。

私はそれが良いと言っているのではありません。そうではなく、リカルドのように時々悪いこともありますが、単純なケースには良い解決策だと思います。

たくさんのことが起こっているので、コメントを振りかけました。

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

char* ReadFile(char *filename)
{
   char *buffer = NULL;
   int string_size, read_size;
   FILE *handler = fopen(filename, "r");

   if (handler)
   {
       // Seek the last byte of the file
       fseek(handler, 0, SEEK_END);
       // Offset from the first to the last byte, or in other words, filesize
       string_size = ftell(handler);
       // go back to the start of the file
       rewind(handler);

       // Allocate a string that can hold it all
       buffer = (char*) malloc(sizeof(char) * (string_size + 1) );

       // Read it all in one operation
       read_size = fread(buffer, sizeof(char), string_size, handler);

       // fread doesn't set it so put a \0 in the last position
       // and buffer is now officially a string
       buffer[string_size] = '\0';

       if (string_size != read_size)
       {
           // Something went wrong, throw away the memory and set
           // the buffer to NULL
           free(buffer);
           buffer = NULL;
       }

       // Always remember to close the file.
       fclose(handler);
    }

    return buffer;
}

int main()
{
    char *string = ReadFile("yourfile.txt");
    if (string)
    {
        puts(string);
        free(string);
    }

    return 0;
}

それが役に立つか、それから何かを学ぶことができるかどうか私に知らせてください:)


2
buffer[string_size] = '\0';代わりに読むべきではありませんstring_size+1か?Afaik実際の文字列はから0string_size-1なり、\0文字はにある必要がありstring_sizeますよね?
aepsil0n 2014年

4
ftellおよびfseekを使用してファイルのサイズを見つけることは安全ではありません:securecoding.cert.org/confluence/display/seccode/…–
Joakim

1
このコードにはメモリリークが含まれているため、ファイルを閉じることはありません。行方不明がありますfclose(handle)
Joakim 2016

1
fclose(handle)と呼ぶタイプミスがあります
。fclose

3
ヌルターミネータを設定する必要をスキップするのcalloc(2)ではなく、malloc(1)を使用できます。

14

テキストファイルが非常に大きく、大量のメモリが必要になる可能性があるため、代わりに文字をコンソールに直接印刷してください。

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

int main() {

    FILE *f;
    char c;
    f=fopen("test.txt","rt");

    while((c=fgetc(f))!=EOF){
        printf("%c",c);
    }

    fclose(f);
    return 0;
}

6

fscanfの代わりに「read()」を使用してください。

ssize_t read(int fildes, void *buf, size_t nbyte);

説明

read()関数はnbyte、開いているファイル記述子に関連付けられているファイルから、がfildes指すバッファにバイトを読み取ろうとしますbuf

次に例を示します。

http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html

その例の作業部分:

f=open(argv[1],O_RDONLY);
while ((n=read(f,l,80)) > 0)
    write(1,l,n);

別のアプローチは、getc/を使用putcして一度に1文字を読み取り/書き込みすることです。効率が大幅に低下します。良い例:http//www.eskimo.com/~scs/cclass/notes/sx13.html


read特定の文字数で読むことができます。バッファをいっぱいにするのに十分な量を読み込んでから、バッファを画面にダンプしてクリアし、ファイルの最後に到達するまで繰り返します。
bta 2010

1

2つのアプローチが頭に浮かびます。

まず、を使用しないでくださいscanf。使用するfgets()パラメータをしてバッファサイズを指定し、改行文字をそのまま残すを使用します。バッファの内容を出力するファイルの単純なループは、ファイルをそのままコピーするはずです。

第二に、使用fread()または一般的なCイディオムfgetc()。ます。これらは、ファイルを固定サイズのチャンクまたは一度に1文字で処理します。

空白で区切られた文字列でファイルを処理する必要がある場合は、fgetsまたはfreadを使用してファイルを読み取り、strtok空白でバッファを分割するなどの方法を使用します。ターゲット文字列はバッファ境界にまたがる可能性があるため、あるバッファから次のバッファへの遷移を処理することを忘れないでください。

scanf読み取りを行うために使用する外部要件がある場合は、フォーマット指定子の精度フィールドを使用して、読み取る可能性のある文字列の長さを制限します。999バイトのバッファを使用している場合scanf("%998s", str);は、nulターミネータ用のスペースを残してバッファに最大998文字を書き込むと言います。バッファより長い単一の文字列が許可されている場合は、それらを2つに分割して処理する必要があります。そうでない場合は、バッファオーバーフローのセキュリティホールを作成せずに、エラーについてユーザーに丁寧に伝える機会があります。

とにかく、常に戻り値を検証し、悪い、悪意のある、または単に不正な入力を処理する方法を考えてください。


1

fgets読み取った文字列のサイズを使用および制限できます。

char *fgets(char *str, int num, FILE *stream);

whileコード内のを次のように変更できます。

while (fgets(str, 100, file)) /* printf("%s", str) */;

0

動的メモリ割り当てを使用してファイル全体を読み取ることはできますが、ファイルが大きすぎるとメモリの問題が発生する可能性があるため、お勧めできません。

したがって、ファイルの短い部分を読んで印刷することをお勧めします。

#include <stdio.h>
#define BLOCK   1000

int main() {
    FILE *f=fopen("teste.txt","r");
    int size;
    char buffer[BLOCK];
    // ...
    while((size=fread(buffer,BLOCK,sizeof(char),f)>0)
            fwrite(buffer,size,sizeof(char),stdout);
    fclose(f);
    // ...
    return 0;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.