fgetsで一行取得するサンプルは多数あるのだけれど一行がバッファサイズ超えたらどうするのというサンプルがあまりなかった。というか意味をなさないのだろうけれど。
int main() { char* txt = new char[1024]; FILE* fp = fopen("test.txt", "r"); bool readable = true; while(readable){ read_1_line(txt, fp);//一行読み込み printf("%s\n", txt); readable = feof(fp) == 0; } getchar(); delete[] txt; return 0; }
バッファサイズが小さいので大抵は一行に収まりきらず複数回fgetsが走る。そしてfgetsがnullptrを返すか、読み込んだ文字列の最後が"\n\0"という並びの時だけループを抜ける。
#include <cstring> void read_1_line(char* txt, FILE* fp) { txt[0] = '\0'; const int BUF_SIZE = 10;//バッファサイズが小さい char buffer[BUF_SIZE]; while(fgets(buffer, BUF_SIZE, fp) ){ strcat(txt, buffer); char* p = strchr(txt, '\n');//改行の削除 if (p) { *p = '\0'; break; } } }
fgetsは改行までを一行と見なして読み込む。大抵は改行が最後に入るのだが入らないこともあるのでこの方法をとる。
(参考)FIO36-C. fgets() が改行文字を読み取ると仮定しない
バッファサイズが10,読み込み文字がそれぞれ以下の時のfgetsで読み込まれる内容。
ファイル内の一行の文字 | 一回目 | 二回目 | コメント |
01234567 | -- | 一回で読み込める。 最後に改行 末尾は'\0' | |
012345678 | 二回にわたって読み込む。 一回目に改行は入らない。 二回目は、一回目で読めなかった'\n'だけが読み込まれる 末尾は [1] 0 '\0' となりnull終端 | ||
0123456789 | 二回にわたって読み込む。 一回目に改行は入らない。 二回目は、一回目で読めなかった'9' '\n' 末尾は [2] 0 '\0' となりnull終端 |
このままでは結局引数txtの要素数に依存してしまうので、結果をどんどんstring型変数へ結合していく。
std::string read_1_line(FILE* fp) { std::string str; const int BUF_SIZE = 10; char buffer[BUF_SIZE]; while (fgets(buffer, BUF_SIZE, fp)) { char* p = strchr(buffer, '\n'); if (p) { *p = '\0'; } str += buffer; if (p)break; } return str;//コピーコスト?知らん。 }
もっともこれをやりだすとそもそもfgetsを使う必要云々という議論に発展する気がする。でもfstreamは嫌いだ。