C++のifstreamの使い方とは?

このQ&Aのポイント
  • C++のifstreamを使ってファイルを読み込む方法について解説します。
  • ifstreamを使用してファイルを読み込む際、ファイルの中身が空だとどのような例外処理が行われるのか疑問に思っています。
  • コードの一部を変更することで、ファイルの中身が存在する場合に正しく動作するようになりますが、その違いについて詳しく教えてください。
回答を見る
  • ベストアンサー

C++のifstreamの使い方

C++のifstreamの使い方で分からない所があるので、分かる方御教示ください。 下記は、C++で読み込んだファイルの中身が空だった場合を無理やり例外処理を使って書いてみたのですが、中身が存在する場合、たとえば、 line1 line2 line3 ではline1を無限に繰り返してしまいます。(1)を ifstream instream = inStream(argv[1]); while (instream >> input) にするとうまくいくようなのですが、この違いがよくわかりません。 違いを教えてください。 #include <iostream> #include <string> #include <fstream> using namespace std; ifstream inStream(char *str); int main(int argc, char *argv[]) { if (argc < 2) cout << "ファイル名を指定してください" << endl; else { try { string input; while (inStream(argv[1]) >> input) // (1) cout << input << endl; } catch (int i) { cerr << argv[1] << "を開けません" << endl; } } return 0; } ifstream inStream(char *str) { ifstream inStream(str); if (!inStream) throw 1; return inStream; }

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8481/19299)
回答No.1

ifstream inStream(str); の行が、何をやっているか、理解してますか? 「strで指定されたファイルをストリームとしてオープンして、ファイルの読み込みポインタを先頭にする」のですよ。 そして return inStream; の行で、オープンしたストリームを「ifstream型の変数」として返しています。 なので while (inStream(argv[1]) >> input) とやると「毎回、argv[1]で指定されたファイルをオープンして、読み込み位置を1行目にする」ってのを繰り返します。 なので「何回ループしようが、1行目しか返って来ない」のです。 しかも、ストリームをクローズしないまま、何度も再オープンを繰り返しているので、何十回か繰り返した段階で、リソースを使い尽くしてオープンエラーが出る筈です。 ともかく「クローズしないでオープンを何度も繰り返す」ってのは、絶対に駄目です。 オープンしたストリームハンドラは「プログラム終了時に自動的にクローズされる」ので、明示的にクローズしない人が殆どですが、本来であれば「ストリームハンドラを変数に受け取って、最後にクローズするべき」なのです。 #include <iostream> #include <string> #include <fstream> using namespace std; ifstream inStream(char *str); int main(int argc, char *argv[]) { if (argc < 2) cout << "ファイル名を指定してください" << endl; else { try { string input; //オープンしていいのは最初の1回だけ! //ストリームハンドラは変数に受け取る ifstream instream = inStream(argv[1]); //受け取った変数でループを回す while (instream >> input) cout << input << endl; } //終わったらちゃんとクローズ! instream.close(); //ここから例外処理 catch (int i) { cerr << argv[1] << "を開けません" << endl; } } return 0; } ifstream inStream(char *str) { ifstream inStream(str); if (!inStream) throw 1; return inStream; }

tmiyoshi
質問者

お礼

詳しい説明ありがとうございました。

その他の回答 (1)

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

>ifstream instream = inStream(argv[1]); >while (instream >> input) >にするとうまくいくようなのですが、この違いがよくわかりません。 >違いを教えてください。 inStream()の中で「毎回、新規にオープンし直す」ので、結果として「毎回先頭から読み込んでいる」んです。 # 正確には…ローカル変数としてifstreamのインスタンス作成して…でしょうかね。 コードに書かれた通り、正常動作していますよ。 # ただし、オープンしたifstreamを閉じていないので、リソースリークしていると思いますが。 ってか… >ifstream inStream(char *str) { >ifstream inStream(str); だと、再帰で永遠に自分呼び出ししません?(吹っ飛ぶまで) # いや、ローカル変数名と関数名が同一だからコンパイルエラー?

関連するQ&A

  • [C++]ファイル出力について

    教えてください。 コマンドプロンプトから何行か書いた文章をファイルにしたいのですが、 うまくいきません。 作ったものの結果は1行1文字で出力されて、eofでうまく 終わってくれません。 コマンドプロンプトで入力(改行)された通りにファイルに出力 できるようにしたいので、どこがおかしいのか指摘お願いします。 #include <iostream> #include <fstream> #include <stdlib.h> #include <string.h> #include <string> using namespace std; int main(int argc, char *argv[]) { char str[100]; int i; i = 0; if (argc <= 1) { cerr << "Need filename" << endl; exit (1); } ifstream ifs(argv[1], ios::in); if (ifs) { cerr << "Caution" << argv[1] << " already exists " << endl; cerr << " Specify a different filename " << endl; exit (2); } ofstream ofs(argv[1], ios::out); if (!ofs) { cerr << " Unable to write to " << argv[1] << endl; exit (3); } while(str[i] !=EOF) { cin >> str[i]; ofs << str[i] << endl; i++; } return 0; }

  • プログラムの動作の仕方

    この下のプログラムは、WRITE <ファイル名>をコマンド行で入力すると、動作するプログラムなのですが、この通りにWRITE <test>としてもできません。 やり方を教えてください. #include <iostream> #include <fstream> using namespace std; int main(int argc,char *argv[]) { if(argc!=2){ cout << "使い方:WRITE<ファイル名>" << endl; return 1; } ofstream out(argv[1]); //出力ファイル if(!out){ cout << "出力ファイルが開けません" << endl; return 1; } char str[80]; cout << "文字列をディスクに書き込み、$で停止します" << endl; do{ cout << ": "; cin >> str; out << str << endl; }while(*str!='$'); out.close(); return 0; } お願いします。

  • プログラムの説明

    C++の初心者です。 ↓のプログラムの動作はさっぱりわかりませんが、それについての説明は具体的に教えていただきたいです。(できれば、詳しく) #include <iostream> #include <string> int getNinzu(int ARGC, char *ARGV[]) throw (char const *){ if(ARGC!=2){ throw "Needs only one argument."; } int ninzu=std::atoi(ARGV[1]); if(ninzu<=0){ throw "Value is too small."; } return ninzu; } #include <cstdlib> #include <ctime> int randfive(){ static bool firsttime=true; if(firsttime){ firsttime=false; std::srand(std::time(NULL)); } return static_cast<int>(static_cast<double>(std::rand())/RAND_MAX*(5+1)); } #include <iomanip> int main(int ARGC, char* ARGV[]){ std::string cmdname=ARGV[0]; int ninzu; try{ ninzu=getNinzu(ARGC,ARGV); std::cout << std::setfill('0'); for (int i = 1; i <= ninzu; ++i) { int score = 0; for (int k = 0; k < 20; ++k) score += randfive(); std::cout << "C" << std::setw(5) << i << " " << score << '\n'; } }catch(char const *str){ std::cerr << str << std::endl << "Usage: " << cmdname << " ninzu" << std::endl; return 1; } }

  • C/C++関数間でのStringクラスの扱い

    以下のようなコードを実行してみましたが思い通りに動いてくれません. "sample"という文字列がstrへとコピーされると思ったのですが. stringクラスのc_str()メソッドはconst char*だと言っているので無理矢理キャストしたのが原因でしょうか.stringクラスは記憶領域を自動で変更してくれるのではないのですか.それともこの挙動は仕様ですか. -------- 以下コード -------- #include <iostream> #include <string> using namespace std; int func(char *); int main(void) {     string str("");     func((char *)str.c_str());     cout << "String: " << str << endl;     return EXIT_SUCCESS; } int func(char *buf) {     buf = "sample";     return 0; } -------- 以上コード --------

  • Sortプログラムについて2

    えっと、前回もSortのプログラムについて、質問させていただいたのですが、このプログラムでは、二つのファイルを使ってソートしてるのですが、一つのファイルだけを使って、それに上書きするためにはどうするればいいでしょうか? 下に、ソースを貼っておきます。 #include <iostream> #include <fstream> #include <list> #include <string> using namespace std; int main() { char Str[255]; list<string> str; int count = 0; ifstream in("ttest", ios::binary | ios::in); if (!in){ cout << "入力ファイルが読み込めない" << endl; exit(1); } ofstream out("out", ios::binary | ios::out); if (!out){ cout << "出力ファイルが読み込めない" << endl; exit(1); } while (!in.eof()){ //!!!! in.getline(Str,255); str.push_back(Str); count++; } str.sort(); list<string>::iterator p; p = str.begin(); while(p!=str.end()){ out << *p << endl; p++; } in.close(); out.close(); getchar(); return 0; } よろしくお願いします。

  • C++でSTLを使った文字列操作

    C++素人です。 第一引数で指定するファイルパスの 拡張子を.datに変更する関数を作っていますがうまくいきません。 STLの使い方が悪いのでしょうか? #include <string.h> using namespace std; char *exchange(const char *fname) { char *file; char *ex; string str; str = fname; ex = ".dat"; str.erase(str.find_last_of('.')+1); file = strcat(str, ex); return file; } int main(int argc, char *argv[]) { char *file = exchange(argv[1]); return 0; }

  • コマンドライン引数

    下記のリストの結果は自分の期待では「真」なのですが 「偽」となります。 なぜなのかわけが分からなくなって質問させて頂きまし た。 (なお後尾の2行はチェックするために入れただけです。) どなたかご教示願えませんでしょうか。 よろしくお願いします。 リスト #include <iostream> using namespace std; int main(int argc, char *argv[]) { if( argv[1] == "yes") { cout << "真です。" << endl; } else { cout << "偽です。" << endl; } cout << " argv[1] は " << argv[1] << " です。" << endl; cout << " argv[2] は " << argv[2] << " です。" << endl; }

  • 固定幅フィールドのテキストデータをifstreamを使って読み込む方法

    固定幅フィールドのテキストデータをifstreamを使って読み込む方法 について教えてください。 計算結果の出力ファイルに1行につき8カラム、20カラム、10カラムのデータがあるとします。 例えば 1.2345671.2345678912345678911.23456789 このデータ行には 1.234567(8カラム幅) 1.234567891234567891(20カラム幅) 1.23456789(10カラム幅) の3つの固定小数点の数字が書かれています。 上記例のように3つ(複数)の数字が必ずしもホワイトスペース区切りにはなっていないものとします。 これをC++標準ライブラリのifstream や stringstreamを用いて読み込む場合、どのような記述をしなければならないのでしょうか? たとえば、 int main(int argc, char** argv) { double data[3]; char buf[BUFSIZ]; ifstream ifs( argv[1] ); // argv[1] には上記データが書かれたファイル名が入っているとします。 stringstream str; while( !ifs.eof() ) { if( !ifs.getline( buf, BUFSIZ, '\n' ) ) break; str << buf; str >> setw(8) >> data[0] >> setw(20)>> data[1] >> setw(8) >> data[2]; } cout << data[0] << " " << data[1] << " " << data[2] << endl; return 0; } のような書き方だと、以下のように出力されてしまい、幅を指定しているsetw()が効いていません。 1.23457 0.234568 0.234568 恐らく、'.'がセパレータとして使われて読み込まれているものと思います。 sscanf( buf, "%8lf%20lf%10lf", &data[0], &data[1], &data[2] ); を使うしか方法が無いのでしょうか? 開発環境は ubuntu上のg++ 4.4.3 です。

  • C++文字列の挿入、結合のコードについて

    実行結果のような出力をするためには、 以下のコードの(ウ)(エ)(オ)の部分には何を入れたらよいのでしょうか? よろしくお願いします。 #include <iostream> #include <string> using namespace std; int main( ) { string str1="ABCDEF"; string str2="0123"; string str3; string q; do { (ウ) ; cout << str3 << endl; (エ) ; cout << str1 << endl; cout << "quit?"; cin >> q; } while ( (オ) ); cout << "終了" << endl; return 0; } <実行結果(出力結果)> ABCDEF0123 ABC123DEF quit?q ABC123DEF0123 ABC123123DEF quit?qu ABC123123DEF0123 ABC123123123DEF quit?quit 終了

  • C言語のシェルプログラミングの課題が分かりません。

    C言語のシェルプログラミングを作れという課題で、以下のように作ったんですが、実行して何度かコマンドを入力した後、exitによって一発で終わらせることができません。どのように書き換えればいいか教えて下さい。 また、他にも書き換えた方がよいと思えるところがあったら是非教えて下さいm(_ _)m #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include MAX_ARGS 10 #include MAX_LEN 100 extern char **environ; void child(int argc, char *argv[MAX_ARGS]); int main(void){ int argc, n = 0; int status; char input[MAX_LEN], *argv[MAX_ARGS], *cp; const char *delim = "\t\n"; while (1){ ++n; printf("$ "); fflush(stdout); if(fgets(input, sizeof(input), stdin) == NULL){ break; } cp = input; for(argc = 0; argc < MAX_ARGS; argc++){ if((argv[argc] = strtok(cp, delim)) == NULL) break; cp = NULL; } if(strcmp(argv[0], "exit") == 0){ exit(0); } pid_t pid = fork(); if(pid == -1){ perror("fork"); exit(1); }else if(pid == 0){ child(argc, argv); }else{ wait(&status); } } return 0; } void child(int argc, char *argv[MAX_ARGS]{ execvp(argv[0], argv); }