A Tour of C++ : 10장 입력과 출력
.
10. 입력과 출력
10.1 소개
입출력 스트림 (I/O Stream)
텍스트와 수치 값에 대한 Formatted / Unformatted Buffered I/O 지원.
ostream / istream 타입 있는 값(‘c’, 123, (123,45)과 바이트 시퀀스 사이를 스트림 버퍼를 통해 변환.
타입 민감성 보장, 사용자 정의 타입에 맞게 확장 가능.
이러한 스트림 이용 std::string 의 입출력과 string 버퍼를 이용한 형식화, 파일 입출력 가능.
모든 입출력 스트림 클래스는 소유 자원(버퍼, 파일핸들 등)을 해제하는 소멸자를 포함. ‘자원 획득이 곧 초기화’(RAII)의 한 예.
10.2 출력
<ostream> 에서 모든 내장 타입 출력 연산 정의. << 연산자는 ostream타입의 객체 출력 연산자. cout 은 표준 출력 스트림, cerr 은 에러 보고 표준 스트림. cout 출력값은 기본적으로 문자 시퀀스.
cout << ‘Value of i=” << i << ‘\n’;
10.3 입력
<istream>
>> 연산은 입력 연산자, cin 은 표준 입력 스트림, >> 의 오른쪽 항은 어떤 입력이 허용되고 대상이 무엇인지 결정.
int i;
cin >> i; // 정수를 i에 읽음.
int i;
double d;
cin >> i >> d; // i와 d에 읽기
띄어쓰기와 개행 문자를 비롯한 공백 문자는 읽기를 종료시킴.
한 행 전체를 읽으려면 getline() 함수.
10.4 입출력 상태
iostream 연산의 성공 여부를 알 수 있는 상태.
vector<int> read_ints(istream& is)
{
vector<int> res;
for (int i; is>>i; )
res.push_back(i);
return res;
}
is>>i 연산이 true를 반환하는지 검사.
vector<int> read_ints(istream& is, const string& terminator)
{
vector<int> res;
for (int i; is >> i; )
res.push_back(i);
if (is.eof()) // 파일의 끝. 정상 종료.
return res;
if (is.fail()) { // 실패.
is.clear(); // 상태를 good()으로 리셋
is.unget(); // 숫자가 아닌 무언가를 스트림으로 되돌림.
string s;
if (cin>>s && s == terminstor)
return res;
cin.setstate(ios_base::failbit); // cin 상태에 fail() 추가.
}
return res;
}
auto v = read_ints(cin, “stop”);
10.5 사용자 정의 타입의 입출력
struct Entry {
string name;
int number;
}
ostream& operator<<(ostream& os, const Entry& e)
{
return cout << “{\”” << e.name << “\”, “ << e.number << “}”;
}
입력 연산자는 형식체크와 에러처리 따로 해야해서 더 복잡.
istream& operator>>(...)
{
// { 로 시작
// 문자를 모두 name 으로 저장
// {로 닫고, number 읽기.
// 첫 문자가 {가 아닌 경우 ios_base::failbit 를 기록하고(is.setstate(ios_base::failbit) ) return is;
10.6 형식화
iostream 입력과 출력의 형식을 제어하는 데 필요한 다양한 연산 제공. 조정자(manipulator). ios, istrea, ostream, iomanip 에서 찾을 수 있음.
ex)
cout << 1234 << ‘,’ << hex << 1234 << ‘,’ << oct << 1234 << ‘\n’; // 1234, 4d2, 2322 출력
cout << d << “; “ // 기본 형식 입력/저장
<< scientific << d << “; “ // 1.123e2 스타일
<< hexfloat << d << “; “ // 16진수
<< fixed << d << “; “ // 123.456 스타일
<< defaultfloat << d << ‘\n’; // 기본 형식
cout.precision( n ) 으로 전체 숫사 자릿수+소수점 자릿수를 설정.
10.7 파일 스트림
<fstream> ifstream(읽기), ofstream(쓰기), fstream(읽기/쓰기)
ofstream ofs {“target”};
if (!ofs)
error(“‘target’을 쓰기용으로 열 수 없음“);
ifstream ifs {“source’};
if (!ifs)
error(“‘source’를 읽기용으로 열 수 없음.”);
10.8 문자열 스트림
<sstream> 은 string 읽고 쓰기 스트림.
istringstream(읽기), ostringstream(쓰기), stringstream(읽고/쓰기)
void test()
{
ostringstream oss;
oss << “{temperature,” << scientific << 123.4567890 << “}”;
cout << oss.str() << ‘\n’;
}
istringstream 에서 읽어들인 결과는 str()로 확인.
10.9 C 스타일 입출력
표준 라이브러리 printf(), scanf(). 타입과 보안 측면에서 안전하지 않아 비추천. C스타일 입출력 사용하지 않는 상황에서 입출력 성능을 고려해야 한다면
ios_base::sync_with_stdio(false); // 큰 오버헤드 피할 수 있음
호출하지 않으면 C스타일 입출력 호환성 유지를 위해 iostream 이 매우 느려질 수 있음.
10.10 파일 시스템
파일 시스템 라이브러리, 일관된 인터페이스 제공 <filesystem>
- 파일 시스템 경로 표현과 파일 시스템 탐색
- 파일 타입과 권한 확인
유니코드도 지원. (자세한 정보= cppreference, 부스트 파일 시스템 문서 참고)
path f = “dir/hypotherical.cpp”;
assert( exists(f) );
if (is_regular_file(f))
cout << f << “ 는 파일. 크기는 “ << file_size(f) << ‘\n’;
path 클래스 = 다양한 운영체제 기본 문자 집합과 관례를 처리하는 복잡 클래스. 특히, main() 의 파일 이름 처리 가능.
int main( int argc, char* argv[] )
{
...
path p {argv[1]}; // 커맨드라인으로부터 path 생성
cout << p << “ “ << exists(p) << ‘\n’; .// path 는 문자열로 출력 가능.
}
void use(path p)
{
ofstream f {p};
if (!p) error(“잘못된 파일 이름: “, p);
}
파일 시스템 타입(일부)
path 디렉터리 경로
filesystem_error 파일 시스템 예외
directory_entry 디렉터리 항목
directory_iterator 디렉터리 순회
recursive_directory_iterator 디렉터리와 그 하위 디렉터리 순회
void print_directory(path p)
try {
if ( is_directory(p) ) {
cout << p << “:\n”;
for ( const directory_entry& x : directory_iterator{p} )
cout << “ “ << x.path() << ‘\n’;
}
}
catch ( const filesystem_error& ex ) {
cerr << ex.what() << ‘\n’;
}
void use()
{
print_directory(“.”); // 현재 디렉터리
print_directory(“..”); // 부모 디렉터리
print_directory(“/”); // 유닉스 루트 디렉터리
print_directory(“c:”); // 윈도우 볼륨 C
for ( string s; cin >> s; )
print_directory(s);
}
하위 디렉터리 나열 recursive_directory_iterator{p}
경로 연산(일부) (p, p2는 path)
value_type 파일 시스템의 기본 인코딩에 사용하는 문자 타입
string_type std::basic_string<value_type>
const_iterator path의 value_type에 대한 const 양방향 반복자.
iterator const_iterator의 별칭.
p=p2 p2를 p에 대입
p/=p2
p+=p2
p.native()
p.string()
p.generic_string()
p.filename() p의 파일 이름 부분.
p.stem() p의 꼬리(stem) 부분.
p.extension() p의 파일 확장자(.을 제외한 확장자)
p.begin()
p.end()
p==p2, p!=p2
p<p2, p<=p2, p>p2, p>=p2
is>>p, os<<p p에 스트림 입출력
u8path(s) UTF-8 인코딩된 s로부터 path 생성
파일 시스템 연산(일부)(p, p1, p2는 path)
exists(p)
copy(p1,p2)
copy(p1,p2,e)
b=copy_file(p1,p2)
b=create_directory(p)
b=create_directories(p)
p=current_path() // p에 현재 작업 디렉터리 대입
current_path(p) // p에 현재 작업 디렉터리 대입
s=file_size(p) // p의 포함 바이트 수
b=remove(p)
지정된 연산이 실패하면 함수는 filesystem_error 예외 던짐.
error_code 를 추가 인자로 받는 버전 exists(p,e)
질의함수(inquiry function) f는 path나 file_status
is_block_file(f) f가 블록 디바이스인가?
is_character_file(f) 문자 디바이스?
is_directory(f) 디렉터리?
is_empty(f) 빈 파일or빈 디렉터리?
is_fifo(f) 명명된 파이프(named pipe)인가?
is_other(f) 알 수 없는 종류의 파일인가?
is_regular_file(f)
is_socket(f) IPC 소켓인가?
is_symlink(f) 심볼릭 링크(symbolic link)인가?
status_known(f)
10.11 조언
[1] iostream 은 타입 안전성과 타입 민감성, 확장성을 제공\
[4] endl 을 피하라.
[6] 일반적 출력은 cout 을, 에러는 cerr 를.
[10,11] << 와 >> 는 연쇄적으로 사용하라.
.
.
.