C++には標準機能の1つとしてiostream(cin、cout、ファイルfstream、文字列sstream)と呼ばれる入出力ストリームがあります。
また、ファイルや文字列以外の独自ストリームを使うためのストリームバッファ(streambuf)と呼ばれる機能があります。
これらの使い方について説明します。
C++の入出力ストリームは、次のクラスとして提供されています。
ストリームの種類ごとに入出力両用のクラスが用意され、
名前の最初にi、oがついたクラスはそれぞれ入力専用、出力専用のクラスが用意されています。
入出力両用のクラスは、入力専用、出力専用の2つのクラスの機能を兼ね備えたクラスです。
すべてのクラスはnamespace std内にありますので、クラス指定時にstd::を使うか、
using namespaceを使ってstd::内にあることを指定する必要があります。
入力が可能なストリーム(fstream、ifstream、stringstream、istringstream、iostream、istream)の主な機能は次の通りです。
これらのストリームはistreamの派生クラスになっています。
istreamの大まかなインターフェースは以下の通りです。
stringクラスを扱う場合は#include
が必要になります。
#include <iostream>
class istream
{
public:
istream();
istream(streambuf* strbuf);
~istream();
// 引数に対応するキャラクタ列を読み込み、変換してvalに設定
istream& operator>>(bool& val);
istream& operator>>(short& val);
istream& operator>>(unsigned short& val);
istream& operator>>(int& val);
istream& operator>>(unsigned int& val);
istream& operator>>(long& val);
istream& operator>>(unsigned long& val);
istream& operator>>(float& val);
istream& operator>>(double& val);
istream& operator>>(long double& val);
// istreamから読み込み、その内容をstreambufに保存する
// streambufに保存できなくなるか、
// istreamのデータ終端(end of file)まで読み込む
istream& operator>>(streambuf* psbuf);
// pfunc()を呼び出す
istream& operator>>(istream& (*pfunc)(istream& is));
// 1キャラクタ読み込む
int get();
// 1キャラクタ読み込みchに設定
istream& get(char& ch);
// delimの直前までか、(count-1)キャラクタ読むまでbufに読み込む
// count>0であれば最後に'\0'が追加される
// delimが見つかった場合はistreamに残る
istream& get(char* buf,streamsize count,char delim = '\n');
// istreamから読み込み、その内容をstreambufに保存する
// streambufに保存できなくなるか、
// istreamのデータ終端(end of file)まで読み込む
istream& get(streambuf& strbuf);
// istreamから読み込み、その内容をstreambufに保存する
// delimが見つかるか、streambufに保存できなくなるか、
// istreamのデータ終端(end of file)まで読み込む
// delimが見つかった場合はistreamに残る
istream& get(streambuf& strbuf, char delim);
// delimの直前までか、(count-1)キャラクタ読むまでbufに読み込む
// count>0であれば最後に'\0'が追加される
// get()と違い、delimが見つかった場合、delimは捨てられる
istream& getline(char* buf,streamsize count,char delim = '\n');
// delimが見つかるか、countキャラクタ読むまで読み捨てる
// delimが見つかった場合、delimは捨てられる
istream& ignore(streamsize count = 1,int delim = EOF);
// countキャラクタ読むまでbufに読み込む
// istreamのデータ終端(end of file)が見つかった場合は、
// gcount()キャラクタ書き込んでeofbitとfailbitをセットする
istream& read(char* buf,streamsize count);
// 次のうち最後に呼び出したメソッドで消費したキャラクタ数を返す
// read(),readsome(),get(),getline() -> キャラクタ数を返す
// peek(),putback(),unget() -> 0を返す
streamsize gcount() const;
// bufに最大countキャラクタを読み込むが、
// read()と違い、データ待ちをしない範囲で読み込む
// 読み込んだキャラクタ数を返す
streamsize readsome(char* buf,streamsize count);
// 1キャラクタ読み込むが、そのキャラクタを捨てない
int peek();
// chに与えられたキャラクタを直前に読み込んだキャラクタとして戻す
// streambufの実装によっては、このメソッドは失敗する
istream& putback(char ch);
// 直前に読み込んだキャラクタを戻す
// streambufの実装によっては、このメソッドは失敗する
istream& unget();
// ストリームの読み込み位置を、
// 先頭からpos番目のキャラクタに設定する
istream& seekg(pos_type pos);
// ストリームの読み込み位置を、
// dirで指定された位置からpos番目のキャラクタに設定する
// dirは ios_base::beg, ios_base::cur, ios_base::end
istream& seekg(off_type off, ios_base::seekdir dir);
// ストリームの読み込み位置を返す
pos_type tellg();
// ストリーム依存の入力同期動作を実行する
int sync();
// エラー状態(goodbit,eofbit,failbit,badbitのOR)を返す
iostate rdstate() const;
// goodbitがセットされていればtrue
bool good() const;
// eofbitがセットされていればtrue
bool eof() const;
// failbitまたはbadbitがセットされていればtrue
bool fail() const;
// badbitがセットされていればtrue
bool bad() const;
// failbitまたはbadbitがセットされていればtrue
bool operator !() const;
// エラー状態をnewstateに設定する
void clear(iostate newstate = goodbit);
// エラー状態を、rdstate() | newstateに設定する
void setstate(iostate newstate);
// 例外を起こすエラー状態(goodbit,eofbit,failbit,badbitのOR)を返す
iostate exceptions() const;
// 例外を起こすエラー状態を設定する
// 0, goodbit -> 例外なし
// eofbit,failbit,badbitのOR -> 対応するエラー時にthrow
void exceptions(iostate statemask);
// streambufを返す
streambuf* rdbuf() const;
// streambufを設定する。以前のstreambufを返す
streambuf* rdbuf(streambuf* sbuf);
// フォーマット制御フラグを返す
fmtflags flags() const;
// フォーマット制御フラグをflagsに設定する
// 変更前のフォーマット制御フラグを返す
fmtflags flags(fmtflags flags);
// フォーマット制御フラグをflagsでORする
// 変更前のフォーマット制御フラグを返す
fmtflags setf(fmtflags flags);
// フォーマット制御フラグをmaskでANDしてから、flagsでORする
// 変更前のフォーマット制御フラグを返す
fmtflags setf(fmtflags flags, fmtflags mask);
// フォーマット制御フラグをmaskでANDする
void unsetf(fmtflags mask);
...
};
// コンソール入力 (グローバル変数)
extern istream cin;
#include <iostream>
#include <string>
istream& operator>>(istream& is, string& str);
istream& getline(istream& is, string& str, char delim = '\n');
#include <fstream>
class ifstream : public istream
{
public:
ifstream();
// modeは以下のORを指定する
// ios_base::in (入力)
// ios_base::binary (実装依存のテキスト変換を行わない)
// ios_base::ate (終端から開始)
ifstream(const char* filename, openmode mode = ios_base::in);
void open(const char* filename, openmode mode = ios_base::in);
void close();
bool is_open();
...
};
#include <sstream>
class istringstream : public istream
{
public:
istringstream(openmode mode = ios_base::in);
istringstream(const string& str, openmode mode = ios_base::in);
string str() const;
void str(const string& strnew);
...
};
データ入力
operator >>を使うと、与えた引数の参照先にデータを読み込みます。
呼び出されるメソッドは引数の種類にあわせて切り替わります。
関数を与えた場合は、その関数を呼び出します。
ifstream::get()は文字列バッファ、std::getline()はstringに文字列を読み込みます。
文字列の区切りはdelimで与えます。省略した場合は'\n'と等価になります。
ifstream::write()は、生のchar配列を指定された要素だけ出力します。
istringstreamを使ったコード例を示します。
istringstreamは初期化時に渡されたstringをストリームとして読み出すクラスです。
#include <iostream>
#include <sstream>
#include <string>
std::istream& dumpfunc(std::istream& is)
{
std::string str;
int val;
is >> str >> val;
std::cout << str << std::endl;
std::cout << val << std::endl;
return is;
}
int main()
{
std::string str;
char buf1[3];
char buf2[100];
int val1, val2;
std::istringstream is1("ichigo 1 5 ichigopack 15");
std::cout << "[is1]" << std::endl;
is1 >> str >> val1 >> val2 >> dumpfunc;
std::cout << str << std::endl;
std::cout << val1 << std::endl;
std::cout << val2 << std::endl;
std::istringstream is2("ichigo ichigo 15");
std::cout << "[is2]" << std::endl;
std::getline(is2, str, ' ');
is2.get(buf1,3,' ');
is2.read(buf2,100);
std::streamsize count = is2.gcount();
std::cout << str << std::endl;
std::cout << buf1 << std::endl;
std::cout << count << std::endl;
std::cout.write(buf2,count) << std::endl;
return 0;
}
出力結果は以下の通りです。
[is1]
ichigopack
15
ichigo
1
5
[is2]
ichigo
ic
7
higo 15
ifstreamを使ってファイルの読み込みを行うコード例を示します。
初期化時にファイルを開く場合は引数とモード、
初期化後にファイルを開く場合はifstream::open()に引数とモードを渡します。
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream ifs1("testfile1.txt", std::ios::in);
std::string str;
int val;
ifs1 >> str;
std::cout << str << std::endl;
std::ifstream ifs2;
ifs2.open("testfile2.txt", std::ios::in);
ifs2 >> str >> val;
std::cout << str << ' ' << val << std::endl;
return 0;
}
出力結果は以下の通りです。
カスタムデータ入力
operator>>を定義すれば、
intやfloatなど既存のタイプと同じように、
独自のタイプに対してもistreamから入力できるようになります。
コード例を示します。
#include <iostream>
#include <sstream>
struct ichigointfloat
{
int val_i;
float val_f;
};
std::istream& operator>>(std::istream& is, ichigointfloat& val)
{
is >> val.val_i;
is >> val.val_f;
return is;
}
int main()
{
std::istringstream is("15 1.5");
ichigointfloat val;
is >> val;
std::cout << val.val_i << ':' << val.val_f << std::endl;
return 0;
}
出力結果は以下の通りです。
入力フラグ(flags)の制御
istreamには動作を制御するためのフラグがあります。
フラグを変更することで、operator>>の動作を変更できます。
定数 | 機能 |
boolalpha | boolを'true'と'false'で入力 |
skipws | 空白文字を読み飛ばす |
oct | 整数として8進数を入力 (dec,hex,octのうち1つを指定) |
dec | 整数として10進数を入力 (dec,hex,octのうち1つを指定) |
hex | 整数として16進数を入力 (dec,hex,octのうち1つを指定) |
エラー状態と例外
ストリームにエラーが発生すると、rdstate()で返されるフラグが更新されます。
返されるフラグは次の意味を持ちます。
フラグ | 説明 |
ios_base::goodbit | エラーがない状態 |
ios_base::eofbit | ファイル(ストリーム)の終わりが検出された状態 |
ios_base::failbit | データの変換など、論理エラーが検出された状態 |
ios_base::badbit | ストリームに物理エラーが検出された状態 |
rdstate()の各ビットをチェックすることでエラー状態を検出できます。
また、istreamやostreamのメソッドを使うことでも検出できます。
good() | エラーがなければ true (goodbitをチェック) |
eof() | ストリームの終わりが検出されれば true (eofbitをチェック) |
fail() | 論理・物理エラーが検出されれば true (failbit | badbitをチェック) |
bad() | 物理エラーが検出されれば true (badbitをチェック) |
operator!() | fail()と同じです。(failbit | badbitをチェック) |
bad()は論理エラーを無視するため、エラーチェックを行う場合はfail()を使うと良いでしょう。
rdstate()で返されるフラグの例を以下に示します。
#include <iostream>
#include <sstream>
#include <string>
void dump_rdstate(std::istream& is)
{
std::cout << "rdstate: good() = " << is.good()
<< ", eof() = " << is.eof()
<< ", fail() = " << is.fail()
<< ", bad() = " << is.bad() << std::endl;
}
int main()
{
std::string str;
int val;
std::istringstream is1("ichigo");
std::cout << "[is1]" << std::endl;
dump_rdstate(is1);
is1 >> str;
std::cout << str << std::endl;
dump_rdstate(is1);
std::istringstream is2("ichigo ");
std::cout << "[is2]" << std::endl;
is2 >> str;
std::cout << str << std::endl;
dump_rdstate(is2);
std::istringstream is3("1");
std::cout << "[is3]" << std::endl;
is3 >> val;
std::cout << val << std::endl;
dump_rdstate(is3);
std::istringstream is4("1 ");
std::cout << "[is4]" << std::endl;
is4 >> val;
std::cout << val << std::endl;
dump_rdstate(is4);
std::istringstream is5("ichigo 15");
std::cout << "[is5]" << std::endl;
std::getline(is5, str);
std::cout << str << std::endl;
dump_rdstate(is5);
std::istringstream is6("ichigo 15\n");
std::cout << "[is6]" << std::endl;
std::getline(is6, str);
std::cout << str << std::endl;
dump_rdstate(is6);
std::istringstream is7("ichigo 15");
std::cout << "[is7]" << std::endl;
val = 99;
str = "ichigoichigo";
is7 >> val >> str;
std::cout << val << ' ' << str << std::endl;
dump_rdstate(is7);
is7.clear();
is7 >> str;
std::cout << str << std::endl;
dump_rdstate(is7);
return 0;
}
出力結果は以下の通りです。
[is1]
rdstate: good() = 1, eof() = 0, fail() = 0, bad() = 0
ichigo
rdstate: good() = 0, eof() = 1, fail() = 0, bad() = 0
[is2]
ichigo
rdstate: good() = 1, eof() = 0, fail() = 0, bad() = 0
[is3]
1
rdstate: good() = 0, eof() = 1, fail() = 0, bad() = 0
[is4]
1
rdstate: good() = 1, eof() = 0, fail() = 0, bad() = 0
[is5]
ichigo 15
rdstate: good() = 0, eof() = 1, fail() = 0, bad() = 0
[is6]
ichigo 15
rdstate: good() = 1, eof() = 0, fail() = 0, bad() = 0
[is7]
99 ichigoichigo
rdstate: good() = 0, eof() = 0, fail() = 1, bad() = 0
ichigo
rdstate: good() = 1, eof() = 0, fail() = 0, bad() = 0
exceptions()メソッドを呼び出すと、
指定されたビット(goodbit以外)がセットされた場合に例外をthrowさせることもできます。
throwされる例外はios_base::failureクラスで、このクラスはexceptionを継承したクラスです。
#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>
int main()
{
try {
int val;
std::istringstream is("ichigo");
is.exceptions( std::ios::failbit | std::ios::badbit );
std::cout << "[is]" << std::endl;
is >> val;
} catch ( const std::exception& e ) {
std::cout << "exception: " << e.what() << std::endl;
}
return 0;
}
出力結果は以下の通りです。
[is]
exception: ios_base::failbit set: iostream stream error
ストリーム出力
出力が可能なストリーム(fstream、ofstream、stringstream、ostringstream、iostream、ostream)の主な機能は次の通りです。
種類 | メソッド |
データ入力 | operator <<,put(),write() |
ストリーム位置制御 | tellp(),seekp() |
同期 | flush() |
エラー状態の取得 | rdstate(),good(),eof(),fail(),bad(),operator bool,operator ! |
エラー状態の制御 | clear(), setstate() |
例外処理の制御 | exceptions() |
実体(ストリームバッファ)の制御 | rdbuf() |
表示精度の制御 | precision() |
表示幅の制御 | width() |
表示埋め尽くし文字制御 | fill() |
表示フォーマット制御 | setf(), unsetf(), flags() |
これらのストリームはostreamの派生クラスになっています。
ostreamの大まかなインターフェースは以下の通りです。
#include <iostream>
class ostream
{
public:
ostream();
ostream(streambuf* sbuf);
~ostream();
// 値valをキャラクタ列に変換して出力
ostream& operator<<(bool val);
ostream& operator<<(short val);
ostream& operator<<(unsigned short val);
ostream& operator<<(int val);
ostream& operator<<(unsigned int val);
ostream& operator<<(long val);
ostream& operator<<(unsigned long val);
ostream& operator<<(float val);
ostream& operator<<(double val);
ostream& operator<<(long double val);
// streambufから読み込み、その内容をostreamに保存する
// ostreamに保存できなくなるか、
// streambufのデータ終端(end of file)まで読み込む
ostream& operator<<(streambuf* sbuf);
// pfunc()を呼び出す
ostream& operator<<(ostream& (*pfunc)(ostream& os));
// キャラクタchを出力する
ostream& put(char ch);
// dataを先頭とするcountキャラクタを出力する
ostream& write(const char* data,streamsize count);
// ストリームの出力位置を、
// 先頭からpos番目のキャラクタに設定する
ostream& seekp(pos_type pos);
// ストリームの出力位置を、
// dirで指定された位置からpos番目のキャラクタに設定する
// dirは ios_base::beg, ios_base::cur, ios_base::end
ostream& seekp(off_type off, ios_base::seekdir dir);
// ストリームの出力位置を返す
pos_type tellp();
// ストリーム依存の出力同期動作を実行する
ostream& flush();
// エラー状態(goodbit,eofbit,failbit,badbitのOR)を返す
iostate rdstate() const;
// goodbitがセットされていればtrue
bool good() const;
// eofbitがセットされていればtrue
bool eof() const;
// failbitまたはbadbitがセットされていればtrue
bool fail() const;
// badbitがセットされていればtrue
bool bad() const;
// failbitまたはbadbitがセットされていればtrue
bool operator !() const;
// エラー状態をnewstateに設定する
void clear(iostate newstate = goodbit);
// エラー状態を、rdstate() | newstateに設定する
void setstate(iostate newstate);
// 例外を起こすエラー状態(goodbit,eofbit,failbit,badbitのOR)を返す
iostate exceptions() const;
// 例外を起こすエラー状態を設定する
// 0, goodbit -> 例外なし
// eofbit,failbit,badbitのOR -> 対応するエラー時にthrow
void exceptions(iostate statemask);
// streambufを返す
streambuf* rdbuf() const;
// streambufを設定する。以前のstreambufを返す
streambuf* rdbuf(streambuf* sbuf);
// floatを文字列に変換する際の最大精度を返す
streamsize precision() const;
// floatを文字列に変換する際の最大精度をvalに設定する
// 変更前の最大精度を返す
// (実際に変換する際は、これ以下の精度になることもある)
streamsize precision(streamsize val);
// 変換時の最小キャラクタ数を返す
streamsize width() const;
// 変換時の最小キャラクタ数を設定する
// 変更前の最小キャラクタ数を返す
// 変換時に長さが足りない場合はfill()で指定したキャラクタで埋める
// (実際に変換する際は、これ以上のキャラクタ数になることもある)
streamsize width(streamsize val);
// 変換時に長さが足りない場合の埋め尽くしキャラクタを返す
char fill() const;
// 変換時に長さが足りない場合の埋め尽くしキャラクタを設定する
// 変更前の埋め尽くしキャラクタを返す
char fill(char ch);
// フォーマット制御フラグを返す
fmtflags flags() const;
// フォーマット制御フラグをflagsに設定する
// 変更前のフォーマット制御フラグを返す
fmtflags flags(fmtflags flags);
// フォーマット制御フラグをflagsでORする
// 変更前のフォーマット制御フラグを返す
fmtflags setf(fmtflags flags);
// フォーマット制御フラグをmaskでANDしてから、flagsでORする
// 変更前のフォーマット制御フラグを返す
fmtflags setf(fmtflags flags, fmtflags mask);
// フォーマット制御フラグをmaskでANDする
void unsetf(fmtflags mask);
...
};
// コンソール出力 (グローバル変数)
extern ostream cout;
// コンソールエラー出力 (グローバル変数)
extern ostream cerr;
// コンソールログ出力 (グローバル変数)
extern ostream clog;
#include <iostream>
#include <string>
ostream& operator<<(ostream& os, const string& str);
#include <fstream>
class ofstream : public ostream
{
public:
ofstream();
// modeは以下のORを指定する
// ios_base::out (出力)
// ios_base::binary (実装依存のテキスト変換を行わない)
// ios_base::app (出力時、常に終端に追加する形で出力)
// ios_base::ate (終端から開始)
// ios_base::trunc (開く際に既存データを破棄)
ofstream(const char* filename, openmode mode = ios_base::out );
void open(const char* filename, openmode mode = ios_base::out );
void close();
bool is_open();
...
};
#include <sstream>
class ostringstream : public ostream
{
public:
ostringstream( openmode mode = ios_base::out );
ostringstream(const string& str, openmode mode = ios_base::out);
string str() const;
void str(const string& strnew);
...
};
出力フラグ(flags)の制御
定数 | 機能 |
boolalpha | boolを'true'と'false'で出力 |
showbase | 8進数の場合は最初に0、16進数の場合は最初に0xを出力 |
showpoint | floatやdoubleの出力時に小数点('.')を常に出力 |
showpos | 正の値を出力する際に'+'を出力 |
oct | 整数として8進数を出力 (dec,hex,octのうち1つを指定) |
dec | 整数として10進数を出力 (dec,hex,octのうち1つを指定) |
hex | 整数として16進数を出力 (dec,hex,octのうち1つを指定) |
basefield | oct | dec | hex |
fixed | floatやdoubleの出力時に固定点表記を使用 (fixed,scientificのうち1つを指定) |
scientific | floatやdoubleの出力時に科学表記を使用 (fixed,scientificのうち1つを指定) |
floatfield | fixed | scientific |
left | fillで指定された文字を埋める場所を左にする (left,internal,rightのうち1つを指定) |
internal | fillで指定された文字を埋める場所を符号と数字の間にする (left,internal,rightのうち1つを指定) |
right | fillで指定された文字を埋める場所を右にする (left,internal,rightのうち1つを指定) |
adjustfield | left | internal | right |
unitbuf | 毎回flush() |
uppercase | ostreamが文字を生成する場合に小文字ではなく大文字を使用 |
これらのフラグはios_baseクラス内で定義されていますが、
C++にはフラグと同じ名前の関数も存在します。
ios_base::を前に追加した場合はフラグ、そうでない場合は関数の名前になります。
出力フラグの制御例
フラグ制御を行うコードの例を示します。
#include <iostream>
int main()
{
std::cout << "[1]" << std::endl;
bool ichigobool = true;
std::cout.unsetf(std::ios_base::boolalpha);
std::cout << ichigobool << std::endl;
std::cout.setf(std::ios_base::boolalpha);
std::cout << ichigobool << std::endl;
std::cout << "[2]" << std::endl;
std::cout.unsetf(std::ios_base::showbase);
std::cout.setf(std::ios_base::oct, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout.setf(std::ios_base::dec, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout << "[3]" << std::endl;
std::cout.setf(std::ios_base::showbase);
std::cout.setf(std::ios_base::oct, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout.setf(std::ios_base::dec, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout << "[4]" << std::endl;
std::cout.setf(std::ios_base::uppercase | std::ios_base::showbase);
std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout << "[5]" << std::endl;
std::cout.setf(0, std::ios_base::floatfield);
std::cout.setf(std::ios_base::showpoint);
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout.unsetf(std::ios_base::showpoint);
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout.setf(std::ios_base::scientific, std::ios_base::floatfield);
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout << "[6]" << std::endl;
std::cout.fill('*');
std::cout.setf(std::ios_base::dec, std::ios_base::basefield);
std::cout.setf(std::ios_base::left, std::ios_base::adjustfield);
std::cout.width(10);
std::cout << -15 << ' ' << -15 << std::endl;
std::cout.width(10);
std::cout << "ichigo" << std::endl;
std::cout.setf(std::ios_base::internal, std::ios_base::adjustfield);
std::cout.width(10);
std::cout << -15 << ' ' << -15 << std::endl;
std::cout.setf(std::ios_base::right, std::ios_base::adjustfield);
std::cout.width(10);
std::cout << -15 << ' ' << -15 << std::endl;
return 0;
}
出力結果は以下の通りです。
[1]
1
true
[2]
17
15
f
[3]
017
15
0xf
[4]
0XF
[5]
15.0000 1.50000
15 1.5
15.000000 1.500000
1.500000E+01 1.500000E+00
[6]
-15******* -15
ichigo****
-*******15 -15
*******-15 -15
関数を使って書くこともできます。
#include <iostream>
#include <ios>
int main()
{
std::cout << "[1]" << std::endl;
bool ichigobool = true;
std::cout << std::noboolalpha;
std::cout << ichigobool << std::endl;
std::cout << std::boolalpha;
std::cout << ichigobool << std::endl;
std::cout << "[2]" << std::endl;
std::cout << std::noshowbase;
std::cout << std::oct;
std::cout << 15 << std::endl;
std::cout << std::dec;
std::cout << 15 << std::endl;
std::cout << std::hex;
std::cout << 15 << std::endl;
std::cout << "[3]" << std::endl;
std::cout << std::showbase;
std::cout << std::oct;
std::cout << 15 << std::endl;
std::cout << std::dec;
std::cout << 15 << std::endl;
std::cout << std::hex;
std::cout << 15 << std::endl;
std::cout << "[4]" << std::endl;
std::cout << std::uppercase << std::showbase;
std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
std::cout << 15 << std::endl;
std::cout << "[5]" << std::endl;
std::cout.unsetf(std::ios_base::floatfield);
std::cout << std::showpoint;
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout << std::noshowpoint;
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout << std::fixed;
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout << std::scientific;
std::cout << 15.0 << ' ' << 1.5 << std::endl;
std::cout << "[6]" << std::endl;
std::cout.fill('*');
std::cout << std::dec;
std::cout << std::left;
std::cout.width(10);
std::cout << -15 << ' ' << -15 << std::endl;
std::cout.width(10);
std::cout << "ichigo" << std::endl;
std::cout << std::internal;
std::cout.width(10);
std::cout << -15 << ' ' << -15 << std::endl;
std::cout << std::right;
std::cout.width(10);
std::cout << -15 << ' ' << -15 << std::endl;
return 0;
}
ファイルへの出力
出力先をファイルとする場合は、コンストラクタに引数とモードを渡すか、
初期化後、ifstream::open()に引数とモードを渡します。
#include <iostream>
#include <fstream>
int main()
{
std::ofstream ofs1("testfile1.txt", std::ios::out);
std::ofstream ofs2;
ofs1 << "ichigopack" << std::endl;
ofs2.open("testfile2.txt", std::ios::out);
ofs2 << "ichigopack" << ' ' << 15 << std::endl;
return 0;
}
testfile1.txt、testfile2.txtへの出力結果はそれぞれ以下の通りです。
カスタムデータ出力
独自のoperator<<を実装すれば、
既存のタイプと同じように独自のタイプを出力できるようになります。
#include <iostream>
#include <sstream>
struct ichigointfloat
{
int val_i;
float val_f;
};
std::ostream& operator<<(std::ostream& os, const ichigointfloat& val)
{
os << val.val_i << ':' << val.val_f;
return os;
}
int main()
{
ichigointfloat val;
val.val_i = 15;
val.val_f = 1.5;
std::cout << val << std::endl;
return 0;
}
出力結果は以下の通りです。
エラー状態と例外
ストリームにエラーが発生すると、rdstate()で返されるフラグが更新されます。
exceptions()メソッドを呼び出すと、
指定されたビット(goodbit以外)がセットされた場合に例外をthrowさせることもできます。
これらのエラー処理はistreamのエラー処理と同じものです。
ストリームバッファ
fstreamやstringstreamは、入出力の対象としてファイルや文字列を使用します。
しかし、入出力の対象として他の対象を使用したいときもあるでしょう。
fstreamやstringstreamの入出力の対象は、istreamやostreamではなく、
streambufと呼ばれるクラスの派生クラス内で実装されています。
その場合は、streambufクラスを自分で実装することで、
入出力の対象として独自のものを使用できるようになります。
streambufは継承して使うためのクラスで、継承クラス側で必要な機能を独自に実装する形で使います。
種類 | 入出力 | メソッド |
出力バッファ設定 | 出力 | setbuf() |
バッファ位置操作 | 共通 | seekoff(), seekpos() |
同期 | 共通 | sync() |
読み込み | 入力 | showmanyc(),xsgetn() |
書き込み | 出力 | xsputn() |
入力バッファ不足 | 入力 | underflow(),uflow(),pbackfail() |
出力バッファ不足 | 出力 | overflow() |
ロケール変更 | 共通 | imbue() |
streambufの大まかなインターフェースは以下の通りです。
#include <streambuf>
class streambuf
{
public:
streambuf();
~streambuf();
...
protected:
// 入力バッファの開始・現在・終了位置のポインタを設定する
// 一度も呼び出さなければ、すべてNULLが設定されている
void setg(char* ptr_eback, char* ptr_gptr, char* ptr_egptr);
// 入力バッファの開始位置のポインタを返す
char* eback() const;
// 入力バッファの現在位置のポインタを返す
char* gptr() const;
// 入力バッファの終了位置のポインタを返す
char* egptr() const;
// 入力バッファをcountだけ進める
void gbump(int count);
// 出力バッファの開始・現在・終了位置のポインタを設定する
// 現在位置のポインタは開始位置のポインタと同じ位置になる
// 一度も呼び出さなければ、すべてNULLが設定されている
void setp(char* ptr_pbase, char* ptr_epptr);
// 出力バッファの開始位置のポインタを返す
char* pbase() const;
// 出力バッファの現在位置のポインタを返す
char* pptr() const;
// 出力バッファの終了位置のポインタを返す
char* epptr() const;
// 出力バッファをcountだけ進める
void pbump(int count);
...
protected: // istreamのためにstreambufの派生クラスが実装するメソッド
// 入力バッファが終了位置に達した場合に呼び出される
// 読み込み位置を変更せずに、次の1キャラクタを返す
// ストリームの終端であればEOFを返す
// デフォルトではgptr()が指すキャラクタを返す
virtual int underflow();
// 入力バッファが終了位置に達した場合に呼び出される
// 次の1キャラクタを読み込んで、それを返す
// ストリームの終端であればEOFを返す
// デフォルトではunderflow()とgbump()を順に呼び出す
virtual int uflow();
// chがEOFでない場合は、次に読み込むためにキャラクタchを戻す
// このメソッドは失敗しても良い
// 成功した場合はchを、失敗した場合はEOFを返す
// デフォルトでは常にEOFを返す
virtual int pbackfail(int ch);
// 可能であれば残りのキャラクタ数を返す
// 正の値:残りのキャラクタ数
// 0:情報なし
// -1:エラー
// デフォルトでは単に0を返す
virtual streamsize showmanyc();
// countキャラクタ読み込むかストリームの終端までをbufに読み込む
// デフォルトで他のメソッドを使った実装が提供されているが、
// 読み込み効率を上げるために実装しても良い
// 読み込んだキャラクタ数を返す
virtual streamsize xsgetn(char* buf, streamsize count);
protected: // ostreamのためにstreambufの派生クラスが実装するメソッド
// 出力バッファが終了位置に達した場合に呼び出される
// chがEOFでない場合は、chで指定された1キャラクタも出力する
// このメソッドは単に出力しても良いし、出力バッファを更新しても良い
// 成功した場合はchを、失敗した場合はEOFを返す
// デフォルトでは常にEOFを返す
virtual int overflow(int ch);
// dataからcountキャラクタを出力する
// デフォルトで他のメソッドを使った実装が提供されているが、
// 出力効率を上げるために実装しても良い
// 出力したキャラクタ数を返す
virtual streamsize xsputn(const char* data, streamsize count);
protected: // 入出力双方のために、streambufの派生クラスが実装するメソッド
// 入出力バッファをファイルなどの実体と同期させる
// 成功した場合は0、失敗した場合は-1を返す
// デフォルトでは何もせず0を返す
virtual int sync();
// streambufで使えるバッファが提供された場合に呼び出される
// 実装の際には、bufからcountキャラクタ分のバッファを自由に利用して良い
// 戻り値としては常にthisを返す
// デフォルトでは何もせずにthisを返す
virtual streambuf* setbuf(char* buf, streamsize count);
// ストリーム内の位置をdirで指定された開始位置からoffsetの位置に更新する
// 開始位置dirはios_base::beg, ios_base::cur, ios_base::end のいずれか
// modeで指定されたフラグにios_base::inが含まれれば、入力位置を更新する
// modeで指定されたフラグにios_base::outが含まれれば、出力位置を更新する
// ios_base::inとios_base::outの双方が含まれるなら、2つの位置を更新する
// 成功した場合は、更新後のストリーム先頭からのoffsetを返す
// 失敗した場合は-1を返す
// デフォルトでは-1を返す
virtual streampos seekoff(streamoff offset, ios_base::seekdir dir, ios_base::openmode mode);
// seekoff()でdirとしてios_base::begが与えられた場合と同等のメソッド
// デフォルトでは-1を返すため、seekoff()とは別に実装する必要がある
virtual streampos seekpos(streampos offset, ios_base::openmode mode);
...
};
カスタム入力
istreamで入力されたデータを独自の形で保存したい場合は、
streambufを継承し、istreamにstreambufを渡します。
streambufのうち以下の仮想メソッドを独自の形で実装することで、
独自の入出力が可能になります。
virtual int underflow() | 次の読み込み位置にある1キャラクタを返す。次の読み込み位置は変更しない。 |
virtual int uflow() | 次の読み込み位置にある1キャラクタを返し、次の読み込み位置を1つ進める。 |
virtual int pbackfail(int ch) | 最後に読み込んだ1キャラクタ(ch)を次の読み込み位置に戻す。chが最後に読み込んだ1キャラクタと一致しない場合は想定しなくてよい。 |
例として、メンバ変数m_ichigoにキャラクタを保存する場合のコードを以下に示します。
#include <iostream>
#include <streambuf>
#include <string>
#include <algorithm>
const char g_str_ichigo[] = "ichigo 15";
const int g_ichigolen = 9;
class ichigoistreambuf : public std::streambuf
{
public:
ichigoistreambuf();
virtual int underflow() override;
virtual int uflow() override;
virtual int pbackfail(int ch) override;
private:
char m_ichigo[g_ichigolen];
int m_offset;
};
ichigoistreambuf::ichigoistreambuf()
{
std::copy( &g_str_ichigo[0], &g_str_ichigo[g_ichigolen], &m_ichigo[0] );
m_offset = 0;
}
int ichigoistreambuf::underflow()
{
if ( m_offset < g_ichigolen ) return m_ichigo[m_offset];
return EOF;
}
int ichigoistreambuf::uflow()
{
if ( m_offset < g_ichigolen ) return m_ichigo[m_offset++];
return EOF;
}
int ichigoistreambuf::pbackfail(int ch)
{
if ( m_offset > 0 && ch == m_ichigo[m_offset-1] ) {
m_offset --;
return ch;
}
return EOF;
}
int main()
{
ichigoistreambuf sbuf1;
ichigoistreambuf sbuf2;
std::istream is(&sbuf1);
std::string str;
int val;
is >> str >> val;
std::cout << str << std::endl;
std::cout << val << std::endl;
std::cout << &sbuf2 << std::endl;
return 0;
}
出力結果は以下の通りです。
streambufは内部バッファへのポインタを保持し、内部バッファを利用した入出力を行う機能があります。
静的な内部バッファを用いる場合は、コンストラクタでsetg()メソッドを呼び出して内部バッファへのポインタを登録することもできます。
入力用の内部バッファにはsetg()、出力用の内部バッファにはsetp()を使います。
setg()を用いたコード例を示します。
#include <iostream>
#include <streambuf>
#include <string>
#include <algorithm>
const char g_str_ichigo[] = "ichigo 15";
const int g_ichigolen = 9;
class ichigoistreambuf : public std::streambuf
{
public:
ichigoistreambuf();
private:
char m_ichigo[g_ichigolen];
};
ichigoistreambuf::ichigoistreambuf()
{
std::copy( &g_str_ichigo[0], &g_str_ichigo[g_ichigolen], &m_ichigo[0] );
setg( &m_ichigo[0], &m_ichigo[0], &m_ichigo[g_ichigolen] );
}
int main()
{
ichigoistreambuf sbuf1;
ichigoistreambuf sbuf2;
std::istream is(&sbuf1);
std::string str;
int val;
is >> str >> val;
std::cout << str << std::endl;
std::cout << val << std::endl;
std::cout << &sbuf2 << std::endl;
return 0;
}
出力結果は以下の通りです。
内部バッファを動的に設定したい場合は、underflow()とuflow()のタイミングでsetg()メソッドを呼び出して、
内部バッファへのポインタを登録します。コード例を示します。
#include <iostream>
#include <streambuf>
#include <string>
#include <algorithm>
const char g_str_ichigo1[] = "ichigo 15";
const char g_str_ichigo2[] = "151515";
const int g_ichigo1len = 9;
const int g_ichigo2len = 6;
class ichigoistreambuf : public std::streambuf
{
public:
ichigoistreambuf();
virtual int underflow() override;
virtual int uflow() override;
private:
char m_ichigo[32];
int m_ichigoreadstep;
};
ichigoistreambuf::ichigoistreambuf()
{
m_ichigoreadstep = 0;
}
int ichigoistreambuf::underflow()
{
if (m_ichigoreadstep == 0) {
m_ichigoreadstep ++;
std::copy( &g_str_ichigo1[0], &g_str_ichigo1[g_ichigo1len], &m_ichigo[0] );
setg( &m_ichigo[0], &m_ichigo[0], &m_ichigo[g_ichigo1len] );
} else if (m_ichigoreadstep == 1) {
m_ichigoreadstep ++;
std::copy( &g_str_ichigo2[0], &g_str_ichigo2[g_ichigo2len], &m_ichigo[0] );
setg( &m_ichigo[0], &m_ichigo[0], &m_ichigo[g_ichigo2len] );
} else {
std::cout << "[ichigoistreambuf EOF]" << std::endl;
}
if (gptr() != egptr()) return *gptr();
return EOF;
}
int ichigoistreambuf::uflow()
{
int ch = underflow();
if (ch != EOF) gbump(1);
return ch;
}
int main()
{
ichigoistreambuf sbuf1;
ichigoistreambuf sbuf2;
std::istream is(&sbuf1);
std::string str;
int val;
is >> str >> val;
std::cout << str << std::endl;
std::cout << val << std::endl;
std::cout << &sbuf2 << std::endl;
return 0;
}
出力結果は以下の通りです。
[ichigoistreambuf EOF]
ichigo
15151515
ichigo 15151515[ichigoistreambuf EOF]
カスタム出力
ostreamについてもistreamと同様に、
streambufを継承し、ostreamにstreambufを渡すことで独自の出力先への出力できます。
その際に実装するostreamのメソッドは次の通りです。
virtual int overflow(int ch) | 1キャラクタ分のデータを出力する。実際に出力せず、内部でキャッシュしても良い。 |
virtual int sync() | 内部でキャッシュしているデータを出力する。 |
例として、与えられたデータをコンソールに出力するコード例を示します。
#include <iostream>
#include <streambuf>
class ichigoostreambuf : public std::streambuf
{
public:
virtual int sync() override;
virtual int overflow(int ch) override;
};
int ichigoostreambuf::sync()
{
std::cout << "[sync]" << std::endl;
return 0;
}
int ichigoostreambuf::overflow(int ch)
{
if ( ch != EOF ) {
if ( ch >= 0x20 ) {
std::cout << '[' << (char)ch << ']';
} else {
std::cout << '[' << "ctrl:" << (int)ch << ']';
}
}
return ch;
}
int main()
{
ichigoostreambuf sbuf;
std::ostream os(&sbuf);
os << "ichigo" << 15 << std::endl;
os << "ichigopack" << std::endl;
return 0;
}
出力結果は以下の通りです。
[i][c][h][i][g][o][1][5][ctrl:10][sync]
[i][c][h][i][g][o][p][a][c][k][ctrl:10][sync]
静的な内部バッファを用いる場合は、コンストラクタでsetp()メソッドを呼び出して内部バッファへのポインタを登録することもできます。
pbase()は内部バッファの開始位置、pptr()は内部バッファの現在位置を返すstreambufのメソッドです。
setp()を用いたコード例を示します。
#include <iostream>
#include <streambuf>
const int g_buflen = 15;
class ichigoostreambuf : public std::streambuf
{
public:
ichigoostreambuf();
const char* data();
std::size_t datalen();
private:
char m_buf[g_buflen];
};
ichigoostreambuf::ichigoostreambuf()
{
setp( &m_buf[0], &m_buf[g_buflen] );
}
const char* ichigoostreambuf::data()
{
return pbase();
}
std::size_t ichigoostreambuf::datalen()
{
return pptr() - pbase();
}
int main()
{
ichigoostreambuf sbuf;
std::ostream os(&sbuf);
std::cout << "[1]" << std::endl;
os << "ichigo" << 15 << std::endl;
std::cout.write( sbuf.data(), sbuf.datalen() ).flush();
std::cout << "[2]" << std::endl;
os << "ichigopack" << std::endl;
std::cout.write( sbuf.data(), sbuf.datalen() ) << std::endl;
return 0;
}
出力結果は以下の通りです。
[1]
ichigo15
[2]
ichigo15
ichigo
内部バッファを動的に設定したい場合は、overflow()が呼び出されるタイミングで内部バッファへのポインタを登録します。
動的に設定する場合のコード例を示します。
#include <iostream>
#include <streambuf>
#include <vector>
const int g_buflen = 15;
class ichigoostreambuf : public std::streambuf
{
public:
ichigoostreambuf();
virtual int overflow(int ch) override;
const char* data();
std::size_t datalen();
private:
std::vector<char> m_buf;
};
ichigoostreambuf::ichigoostreambuf()
{
}
int ichigoostreambuf::overflow(int ch)
{
std::size_t ichigosize_org = m_buf.size();
std::cout << "[overflow]" << std::endl;
m_buf.resize(ichigosize_org+g_buflen);
char* ptr_base = &m_buf[ichigosize_org];
setp(ptr_base, ptr_base+g_buflen);
if (ch != EOF) {
*pptr() = (char)ch;
pbump(1);
}
return ch;
}
const char* ichigoostreambuf::data()
{
return &m_buf[0];
}
std::size_t ichigoostreambuf::datalen()
{
return pptr() - data();
}
int main()
{
ichigoostreambuf sbuf;
std::ostream os(&sbuf);
std::cout << "[1]" << std::endl;
os << "ichigo" << 15 << std::endl;
std::cout.write( sbuf.data(), sbuf.datalen() ).flush();
std::cout << "[2]" << std::endl;
os << "ichigopack" << std::endl;
std::cout.write( sbuf.data(), sbuf.datalen() ) << std::endl;
return 0;
}
出力結果は以下の通りです。
[1]
[overflow]
ichigo15
[2]
[overflow]
ichigo15
ichigopack