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
は機能しません。どうすればこれを解決できますか?
最も簡単な方法は、文字を読み、読み終わった直後にそれを印刷することです。
int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
c
は負の数であり、プレーンなint
はEOF
である可能性があるため、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
に正確にコピーすることはできません。
これをまとまって読むことについては、たくさんの良い答えがあります。すべてのコンテンツを一度にバッファに読み込んで印刷するというちょっとしたコツを紹介します。
私はそれが良いとは言っていません。そうではありません、そして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;
}
それが有用であるか、あなたがそれから何かを学ぶことができるかどうか私に知らせてください:)
テキストファイルは非常に大きくなる可能性があり、多くのメモリが必要になる可能性があるため、代わりに直接コンソールに文字を印刷してください。
#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;
}
代わりに "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
fgets
を使用して、読み取りストリングのサイズを制限することができます。
char *fgets(char *str, int num, FILE *stream);
コードのwhile
を次のように変更できます。
while (fgets(str, 100, file)) /* printf("%s", str) */;
#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;
}
2つのアプローチが頭に浮かぶ。
まず、scanf
を使わないでください。 fgets()
を使用してください。これはバッファサイズを指定するためのパラメータを取り、改行文字はそのまま残します。バッファの内容を表示するファイルの単純なループは、ファイルをそのままコピーします。
次に、fread()
またはfgetc()
と共通のC慣用句を使用します。これらは、ファイルを固定サイズの塊または一度に1文字ずつ処理します。
ファイルを空白で区切られた文字列で処理する必要がある場合は、ファイルを読み取るためにfgets
またはfread
を使用し、バッファを空白で分割するためにstrtok
のようなものを使用します。ターゲット文字列はバッファ境界にまたがる可能性があるので、あるバッファから次のバッファへの遷移を処理することを忘れないでください。
読み取りを行うためにscanf
を使用するという外部要件がある場合は、フォーマット指定子の精度フィールドを使用して読み取る可能性のあるストリングの長さを制限してください。 999バイトのバッファを使っている場合、scanf("%998s", str);
と言うと、バッファに最大998文字を書き込むことになり、ヌルターミネータのための余地が残ります。あなたのバッファより長い単一の文字列が許されるなら、あなたはそれらを2つの部分に分けて処理しなければならないでしょう。そうでなければ、バッファオーバーフローのセキュリティホールを作成せずにユーザーにエラーについて丁寧に伝える機会があります。
とにかく、常に戻り値を検証し、悪い、悪意のある、または単に不正な形式の入力を処理する方法を検討してください。
ファイル全体を動的メモリ割り当てで読み取ることはできますが、ファイルが大きすぎるとメモリの問題が発生する可能性があるため、お勧めできません。
ファイルの短い部分を読んでそれを印刷するほうがよいでしょう。
#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;
}