記事ディレクトリ
I/O
データの入出力(インプット/アウトプットをI/Oと略します)、標準入力デバイスと標準出力デバイスの入出力を標準I/Oといいます。外部ストレージ ディスク上のファイルの入出力は、ファイル I/O と呼ばれます。メモリ内の指定された文字列記憶領域への入出力は、文字列 I/O と呼ばれます。
フロー
データの入出力のプロセスをストリームとして可視化できます。ストリームからデータを取得する操作は「フェッチ」 (入力操作) と呼ばれます。ストリームにデータを追加する操作は、「挿入」(出力) 操作と呼ばれます。
ストリームクラスライブラリ継承システム
- ストリーム クラス ライブラリには、streambuf クラスと ios クラスという 2 つの並列基本クラスがあり、すべてのストリーム クラスは 2 つのうちの 1 つを基本クラスとして使用します。
- streambuf クラスは、バッファに対する低レベルの操作 (バッファの設定、バッファ ポインタの操作、バッファへの文字の格納/取得) を提供します。
- ios_base および ios クラスはストリームの状態を記録し、streambuf のバッファー入出力のフォーマット済みまたはフォーマットなしの変換をサポートします。
- strstreambuf: 文字列を使用して、一連の文字を保存します。streambuf を拡張して、バッファの抽出および挿入操作を実行します。
- filebuf: ファイルを使用して文字シーケンスを保存します。ファイルを開く、読み取り/書き込み、文字の検索が含まれます。
4 つの入出力オブジェクト
C++ では、ユーザーが標準 I/O 操作を実行できるように、cin、cout、cerr、clog という 4 つのクラス オブジェクトが定義されています。cin は istream ストリーム クラスのオブジェクトで、標準入力デバイスのキーボードを表し、最後の 3 つは ostream ストリーム クラスのオブジェクトです。cout は標準出力デバイスモニターを表します。cerr と clog は同じ意味を持ち、どちらもエラー メッセージ出力デバイスの表示を表します。
ostreamストリームの操作
1.演算子<<
<< 演算を連続して使用できるのはなぜですか? <<戻り値は ostream への参照です。<<オーバーロードを連続して使用できます。<< 基本型のオーバーロードを提供します。
2.置く
put 操作は 1 つの文字を出力し、ostream への参照を返します。
cout.put('A').put('B').put('C');
3.書く
書き込み操作は、指定された長さのバッファを出力し、ostream への参照を返します。
char buf[] = "testing!!!";
cout.write(buf, 8);
istreamストリームの操作
1.オペレーター>>
戻り値は istream への参照であり、>> を使用して継続的にオーバーロードできます。>> 基本型のオーバーロードを提供します。
2.取得
get オペレーションは 1 つの文字を読み取り、その文字の ASCII コードとして整数を返します。
int ch = cin.get();
cout << ch << endl;
参考資料も受け取ることができます。
char ch, ch2;
cin.get(ch).get(ch2);
cout << ch << " " << ch2 << endl;
3.ゲットライン
getline 操作は行を読み取ります (Enter キーが押されました)。istream オブジェクトへの参照を返します。getline() 操作と >> の違い: getline は行全体を取得し、>> はスペースに遭遇すると停止します。
char buf[10] = {
0 };
cin.getline(buf, 10);
cout << buf << endl;
char buf2[10] = {
0 };
cin >> buf2;
cout << buf2 << endl;
4.読む
読み取り操作は istream オブジェクトへの参照を返し、空白文字の表示は正しく、指定された数の文字が最後まで読み取られます。
char buf[10] = {
0 };
cin.read(buf, 5);
cout << buf << endl;
5. ピークとプットバック
読み込まずにピークをピークし、プットバックはストリームに文字を追加します。
char c[10], c2, c3;
c2 = cin.get();
c3 = cin.get();
cin.putback(c2);
cin.getline(&c[0], 9);
cout << c << endl;
ファイルストリーム
ostream から派生した ofstream は、ファイルの書き込みに使用されます。
istream から派生した ifstream は、ファイルの読み取りに使用されます。
iostream から派生した fstream は、ファイルの読み取りと書き込みに使用されます。
ファイルを開く
ストリーム オブジェクトが宣言された後、関数 open() を使用してファイルを開くことができます。ファイルを開くことは、ストリームとファイル間の接続を確立することです。関数プロトタイプ:
void open(const char* filename,int mode = ios::out,int prot = _SH_DENYNO);
mode は、ファイルを開くモード、保護モードを示します。ファイルが正常に開かれたかどうかを判断するには、次の 5 つの方法があります。
#include <iostream>
#include <fstream>
#include <cassert>
using namespace std;
int main()
{
ofstream fout;
fout.open("test.txt");
//1
if (fout.is_open())
{
cout << "succ" << endl;
}
else
cout << "failed" << endl;
//2
if (fout.good())
{
cout << "succ" << endl;
}
else
cout << "failed" << endl;
//3
if (fout)
{
cout << "succ" << endl;
}
else
cout << "failed" << endl;
//4
if (!fout)
{
cout << "failed" << endl;
}
else
cout << "succ" << endl;
//推荐使用断言方式
assert(fout);
fout.close();
return 0;
}
ファイルオープンモード
オープンメソッド | 説明 |
---|---|
iso::in | 読み取り用にファイルを開きます (ifstream のデフォルト) |
iso::out | 書き込み用にファイルを開きます (ofstream のデフォルト) |
iso::アプリ | 書き込む前にファイルの終わりを見つける |
iso::ate | ファイルを開いた直後にファイルをファイルの最後に配置します |
iso::トランク | 現在のファイルの内容を破棄します |
iso::nocreate (サポートされなくなりました) | オープンするファイルが存在しない場合、この関数を使用して open() 関数を呼び出しても機能しません。 |
iso::noreplace (サポートされなくなりました) | 開かれるファイルがすでに存在する場合、open() 関数で開こうとするとエラーが返されます。 |
iso::バイナリ | ファイルをバイナリ形式で開きます。デフォルトはテキスト ファイルです。 |
保護モード
#define _SH_DENYRW 0x10 /* deny read/write mode */拒绝对文件进行读写
#define _SH_DENYWR 0x20 /* deny write mode */拒绝写入文件
#define _SH_DENYRD 0x30 /* deny read mode */拒绝文件的读取权限
#define _SH_DENYNO 0x40 /* deny none mode */读取和写入许可
#define _SH_SECURE 0x80 /* secure mode */共享读取,独占写入
ファイルを開くときの注意点
- ファイルを開くには、コンストラクターを使用して開くこともできます。次に例を示します。
ofstream fout("test.txt,ios::out");
-
ファイルを開く方法には、上記の列挙定数のいずれか、または複数の列挙定数で構成されるビットごとの OR 式を使用できます。
-
open メンバー関数を使用してファイルを開くときに、文字ポインター パラメーターで指定されたファイルが存在しない場合は、ファイルが作成されます。
-
open メソッドに ios::ate または ios::app オプションが含まれていない場合、ファイル ポインタは自動的にファイルの先頭、つまりバイト アドレスが 0 に移動されます。
-
実際には、ofstream の out モードを指定することは、out モードと trunc モードを指定することと同じです。
-
デフォルトでは、fstream オブジェクトは in モードと out モードの両方で開かれます。
-
ファイルが in と out の両方で開かれた場合、空にはなりません。
-
in モードを指定せずに out モードのみを使用すると、ファイルの既存のデータは空になります。
-
outとappを同時に指定した場合はクリアされません。
-
ファイルをオープンするときに trunc モードが指定されている場合、同時に in モードが指定されているかどうかに関係なく、ファイルもクリアされます。
フロー状態
オープンメソッド | 説明 |
---|---|
ios::グッドビット | すべてが正常に動作し、エラーは発生せず、入力が終了しません |
ios::eofbit | 入力の終わり |
ios::フェイルビット | 主に不正なデータ (数値を読み取ろうとしたときに文字が見つかったなど) が原因で、I/O 操作が失敗しました。ストリームは引き続き使用でき、フェイルビット ビットも入力の最後に設定されます。 |
ios::バッドビット | (おそらく物理的な) 致命的なエラーが発生しました。ストリームは利用できなくなります。 |
このフラグ ワードの各ステータス ビットに対応して、ios クラスは、ストリームのステータスを検出または設定するための次のメンバー関数も提供します。
bool rdstate(); //返回流的当前状态标志字
bool eof(); //返回非0值表示到达文件尾
bool fail(); //返回非0值表示操作失败
bool bad(); //返回非0值表示出现错误
bool good(); //返回非0值表示流操作正常
bool clear(int flag=0); //将流的状态设置为flag
プログラムの信頼性を高めるためには、プログラム内でI/Oフローの動作が正常かどうかを検出する必要があります。ストリーム操作でエラーが検出された場合、例外処理を使用して問題を解決できます。
ファイルを閉じる
各ファイル ストリーム クラスは、ファイルを閉じるためのメンバー関数 close() を提供します。機能: 開いたファイルの操作が終了したら、ファイル ストリームを対応する物理ファイルから切断するためにファイルを閉じる必要があります。また、ファイル ストリームがファイル バッファに出力されるかどうかに関係なく、最後にコンテンツが確実にファイル バッファに出力されるようにすることができます。いっぱいかどうかに関係なく、対応する物理ファイルにすぐに書き込まれます。ファイル ストリームに対応するファイルが閉じられた後、ファイル ストリームを使用して open メンバー関数を呼び出して他のファイルを開くこともできます。最初にこれをクリアすることをお勧めします。
ファイルの読み取りと書き込み
1.>>和<<
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ofstream fout("test.txt");
fout << "abcd" << " " << 200;
fout.close();
ifstream fin("test.txt");
string s;
int n;
fin >> s >> n;
cout << s << " " << n << endl;
return 0;
}
2. 入れて手に入れる
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;
int main()
{
ofstream fout("test2.txt");
char ch;
assert(fout);
for (int i = 0; i < 26; i++)
{
ch = 'A' + i;
fout.put(ch);
}
fout.close();
ifstream fin("test2.txt");
while (fin.get(ch))
{
cout << ch;
}
return 0;
}
3. 読み書き
以下は、バイナリ ファイルの読み取りと書き込みの概要です。
4. テキストモードとバイナリモードの違い
ファイルをテキストとして開いた場合、文字を書き込むときに、\n が発生すると変換が実行されます。Windows プラットフォーム \n は \r\n に変換され、Linux プラットフォームは変更されず、Mac システム \n は \r に変換されます。\r 変換は行われません。ファイルをバイナリ モードで開くと、文字は変換されずに書き込まれます。ファイルをテキストとして開くとバイナリ データを書き込むこともでき、ファイルをバイナリとして開くとテキストを書き込むこともできます。書き込まれるデータがバイナリかテキストかは、開く方法には関係なく、書き込みに使用される関数に関係します。バイナリ データを書き込むには、write を使用し、対応する read を使用する必要があります。
バイナリファイルの読み書き
バイナリ ファイルはテキスト ファイルとは異なり、テキスト ファイルを含むあらゆる種類のファイルに使用できます。バイナリファイルの読み書きには、istream クラスから継承したメンバ関数 read() と、ostream クラスから継承したメンバ関数 write() を使用できます。ファイルを開くときに列挙定数 ios::binary を使用します。次に例を示します。
ofstream fout("binary.dat",ios::out|ios::binary);
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;
struct Test
{
int a;
int b;
};
int main()
{
Test test = {
100,200 };
ofstream fout("binary.txt", ios::out | ios::binary);
fout.write(reinterpret_cast<char*>(&test),sizeof(Test));
fout.close();
Test test2;
ifstream fin("binary.txt", ios::in | ios::binary);
fin.read(reinterpret_cast<char*>(&test2),sizeof(Test));
cout << test2.a << " " << test2.b << endl;
return 0;
}
文字列が十分に長い場合のファイルの読み取りと書き込み
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;
struct Test
{
int x;
string a;
string b;
};
int main()
{
Test t1;
t1.x = 100;
t1.a = "asdfsdafasfdasdfasdffsdfsdafadsadsfdfsfdsafdasfdsadfasdsfaasfddsfsadfsdfafdsasadffads";
t1.b = "qwerqwerqrwewqrrqewewrewrqrqewerwqrewqqwerrweqrewqreqwerqwrqewrqweqrwerweqqrwerqwerwesfadsfafdfadsasfasdafsqrw";
ofstream fout("test4.txt", ios::out | ios::binary);
fout.write((char*)(&t1.x),sizeof(int));
int len;
len = t1.a.length();
fout.write((char*)&len, sizeof(int));
fout.write(t1.a.data(), t1.a.length());
len = t1.b.length();
fout.write((char*)&len, sizeof(int));
fout.write(t1.b.data(), t1.b.length());
fout.close();
ifstream fin("test4.txt", ios::in | ios::binary);
Test t2;
fin.read((char*)(&t2.x),sizeof(int));
fin.read((char*)(&len), sizeof(int));
t2.a.resize(len);
fin.read(&t2.a[0], len);
fin.read((char*)(&len), sizeof(int));
t2.b.resize(len);
fin.read(&t2.b[0], len);
cout << t2.x << " " << t2.a << " " << t2.b << endl;
return 0;
}
現在のファイルストリームアクティビティポインタ
ファイル ストリーム ポインタは、I/O 操作が発生する場所を追跡するために使用されます。文字がストリームから読み取られるか、ストリームに書き込まれるたびに、現在のアクティビティ ポインタが進められます。open メソッドに ios::ate または ios::app オプションが含まれていない場合、ファイル ポインタは自動的にファイルの先頭、つまりバイト アドレスが 0 に移動されます。
ファイルseekpおよびseekkgのランダムな読み取りおよび書き込み
- Seekp: 出力ファイル ストリームのファイル ストリーム ポインタ位置を設定します。
- seekg: 入力ファイルストリームのファイルストリームポインタ位置を設定します。
関数パラメーター: pos 新しいファイル ストリーム ポインターの位置、off にはオフセット値が必要、dir 検索開始位置。
ファイル Tellp および Tellg のランダムな読み取りおよび書き込み
- Tellp: 出力ファイルストリームポインタの現在位置をバイト単位で取得します。
- Tellg: 入力ファイルストリームポインタの現在位置をバイト単位で取得します。
関数の戻り値は実際にはlong型です。
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;
struct Test
{
int x;
string a;
string b;
};
int main()
{
ifstream fin("test5.txt");
assert(fin);
fin.seekg(2);
char ch;
fin.get(ch);
cout << ch << endl;
fin.seekg(-1, ios::end);
fin.get(ch);
cout << ch << endl;
fin.seekg(0, ios::end);
streampos pos = fin.tellg();
cout << pos << endl;
return 0;
}
シークディレクトリ
dir パラメータは、ファイル ストリーム ポインタの位置を特定するために使用され、検索の開始位置を表します。ios で定義されている列挙型:
enum seek_dir{
beg,cur,end};
begはファイルストリームの開始位置を示し、curはファイルストリームの現在位置を示し、endはファイルストリームの終了位置を示す。
出力ストリームのフォーマット
データの入出力のフォーマットは、システム ヘッダー ファイルで提供されるマニピュレータを使用して制御されます。これらを挿入演算子 << の出力オブジェクトとして使用するだけです。setiosflags、setw、setfill、setprecision、hex、oct など。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n = 64;
double d = 123.45;
double d2 = 0.0187;
//通过操纵子方式进行格式化输出
cout << "====================宽度控制====================" << endl;
cout << n << "#" << endl;
cout << setw(10) << n << "#" << endl; //默认右对齐
cout << setw(10) << n << "#" << n << endl; //宽度控制不会影响下一个输出
cout << "====================对齐控制====================" << endl;
cout << setw(10) << setiosflags(ios::left) << n << "#" << endl; //设置左对齐
cout << setw(10) << n << "#" << endl; //对齐控制影响下一个输出
cout << setw(10) << setiosflags(ios::right) << n << "#" << endl; //设置右对齐
cout << setw(10) << resetiosflags(ios::left) << n << "#" << endl; //取消左对齐
cout << "====================对齐控制====================" << endl;
cout << setw(10) << setfill('?') << n << "#" << endl;
cout << setw(10) << n << "#" << endl; //填充控制影响下一个输出
cout << setw(10) << setfill(' ') << n << "#" << endl;
cout << "====================精度控制====================" << endl;
cout << setprecision(4) << d << endl; //保留四位有效数字
cout << setprecision(2) << d2 << endl;
cout << setiosflags(ios::fixed);
cout << setprecision(4) << d << endl; //保留小数点后四位
cout << setprecision(2) << d2 << endl;
cout << "====================进制输出====================" << endl;
cout << n << endl;
cout << dec << n << endl;
cout << oct << n << endl;
cout << hex << n << endl;
cout << endl;
cout << setiosflags(ios::showbase);
cout << dec << n << endl;
cout << oct << n << endl;
cout << hex << n << endl;
cout << endl;
cout << setbase(10) << n << endl;
cout << setbase(8) << n << endl;
cout << setbase(16) << n << endl;
return 0;
}
形式は、setf、unsetf、width、fill、precision などのストリームのメンバー関数を呼び出すことによって制御されます。フォーマット設定中に以前の設定に戻すことができるので、元の設定に戻すのに便利です。
#include <iostream>
using namespace std;
int main()
{
int n = 64;
double d = 123.45;
double d2 = 0.0187;
cout << "====================宽度控制====================" << endl;//宽度控制不会影响下一个输出
cout << n << "#" << endl;
cout.width(10);
cout << n << "#" << endl;
cout << n << "#" << endl;
cout << "====================对齐控制====================" << endl;//对齐控制影响下一个输出
cout.width(10);
cout.setf(ios::left);
cout << n << "#" << endl;
cout.width(10);
cout << n << "#" << endl;
cout.width(10);
cout.unsetf(ios::left);
cout << n << "#" << endl;
cout.width(10);
cout.setf(ios::right);
cout << n << "#" << endl;
cout << "====================对齐控制====================" << endl;//填充控制影响下一个输出
cout.width(10);
cout.fill('?');
cout << n << "#" << endl;
cout.width(10);
cout << n << "#" << endl;
cout.width(10);
cout.fill(' ');
cout << n << "#" << endl;
cout << "====================精度控制====================" << endl;
cout.precision(4);//保留四位有效数字
cout << d << endl;
cout.precision(2);
cout << d2 << endl;
cout.setf(ios::fixed);
cout.precision(4);//保留小数点后四位
cout << d << endl;
cout.precision(2);
cout << d2 << endl;
cout << "====================进制输出====================" << endl;
cout.setf(ios::showbase);
cout << n << endl;
cout.unsetf(ios::dec);
cout.setf(ios::oct);
cout << n << endl;
cout.unsetf(ios::showbase);
cout << n << endl;
return 0;
}