web-dev-qa-db-ja.com

Cでは、テキストファイルを読み、すべての文字列を印刷する方法

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

このファイルを読み込み、その内容をコンソールに出力できるCプログラムを作成したい(ファイルにはASCII textしか含まれていないとします)。

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

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

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

78
Richard

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

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

cは負の数であり、プレーンなintEOFである可能性があるため、charは上記のunsignedです。

動的にメモリを割り当てずに、ファイルをまとめて読みたい場合は、次のようにします。

#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 */
}

形式として%sを指定したfscanf()の方法では、ファイル内の空白に関する情報が失われるため、ファイルをstdoutに正確にコピーすることはできません。

119
Alok Singhal

これをまとまって読むことについては、たくさんの良い答えがあります。すべてのコンテンツを一度にバッファに読み込んで印刷するというちょっとしたコツを紹介します。

私はそれが良いとは言っていません。そうではありません、そしてRicardoが時々悪いことになるかもしれませんが、私はそれが単純なケースのための素晴らしい解決策であると思います。

多くのことが起こっているので、私はそれをコメントで振りかけました。

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

それが有用であるか、あなたがそれから何かを学ぶことができるかどうか私に知らせてください:)

51
lfzawacki

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

#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;
}
12
Sagar Shah

代わりに "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);

もう1つの方法は、getc/putcを使用して、一度に1文字ずつ読み書きすることです。はるかに効率が悪いです。良い例: http://www.eskimo.com/~scs/cclass/notes/sx13.html

5
DVK

fgets を使用して、読み取りストリングのサイズを制限することができます。

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

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

while (fgets(str, 100, file)) /* printf("%s", str) */;
1
Edu
#include <stdio.h>
#include <stdlib.h>
int main() {

int num;
FILE *fptr; 



if ((fptr = fopen("/root/Desktop/my_pass.txt","r")) == NULL) {       // checks if file exists
    puts("File not exists");
    exit(1);                    // for exit(1) is required #include <stdlib.h> 
} else 

fscanf(fptr,"%d", &num);                

printf("My pass is:  %d\n", num);           
fclose(fptr); 

return 0;
}
1
Odin

2つのアプローチが頭に浮かぶ。

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

次に、fread()またはfgetc()と共通のC慣用句を使用します。これらは、ファイルを固定サイズの塊または一度に1文字ずつ処理します。

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

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

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

0
RBerteig

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

ファイルの短い部分を読んでそれを印刷するほうがよいでしょう。

#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;
}
0
rigon