-
C++ Primer CH8. The IO Libraryc++ 2024. 1. 21. 16:22
지금까지 우리는 유저 콘솔에 찍히고 입력받는 IO 클래스(cin, cout)만 사용했었다.
근데, 파일을 읽고 써야 할 때는 무엇을 사용하는가?
여러가지 IO 타입들
w 붙으면 wide string(wchar_t) 지원
Relations among the IO Types
IO type들은 클래스로서 상속관계에 있기 때문에 모두 같은 연산자(>>, <<)를 콘솔 윈도우, 파일, 스트링에 관계없이 사용할 수 있다.
모든 ostream류 타입들은 ostream을 상속받았고, istream류 타입들 역시 istream을 상속받았기 때문에, >>나 <<를 사용할 수 있다.
getline 역시 파일, 스트링도 읽어들일 수 있다.
No Copy or Assign for IO Objects
IO obect들은 복사되거나 할당할 수 없다.
ofstream out1, out2; out1 = out2; // error 할당 안됨 ofstream print(ofstream); // error 초기화 안됨 out2 = print(out2); // error 복사 불가
Condition States
stream object가 제대로 값을 읽거나 받았는지 확인하는 가장 쉬운 법은 if () 안의 conditon으로 사용하는 것이다. 올바르지 않은 입,출력일 경우 IO object는 error state가 되면서 정상 object를 반환하지 않게 된다.
Interrogating the State of a Stream
스트림의 상태가 invalid한데, 왜 invalid한지에 대해 알고 싶을 때 방법이 있다.
스트림의 상태를 알려주는 strm::iostate 타입인 4가지 상태비트들
8.13 Managing the Output Buffer
os << “ssss”;
위 작업이 수행될 때, 바로 literal이 출력될 수도 있지만, OS가 버퍼에 저장해두었다가 출력할 수도 있다.
flush되는 경우
- 프로그램이 정상적으로 완료될 때(main return)
- 버퍼가 꽉 찼을 때 버퍼에 쓰기전에 flush
- endl로 명시적 flush
- unitbuf 조작기 쓰면 스트림 버퍼 비움. cerr은 unitbuf와 연동돼 있어서 자동으로 출력시 flush함
- cin, cerr 쓰면 cout의 버퍼가 flush됨
Flushing Manipulators
- endl
- flush + new line
- flush
- only flush
- ends
- add ‘\0’ + flush
- unitbuf
- 모든 write 작업이 끝난 후 flush
Buffers Are Not Flushed If The Program Crashes
프로그램이 충돌나서 작동 멈추면, 출력버퍼에 데이터가 남아 있는 상태다.
따라서 출력이 되었다고 생각하고 그걸 찾으려고 하다가 시간 낭비할 수 있다.
Tying Input and Output Streams
cin.tie(&cout); // cin은 cout와 tied -> cin 사용시 cout 버퍼 flushed ostream *old_tie = cin.tie(nullptr); // -> cout과 tied 해제하고 반환값으로 cout 받기 cin.tie(&cerr); // cin-cerr tied cin.tie(old_tie); // 다시 cin-cout tied
8.2 File Input and Output
fstream 헤더는 3가지 타입이 있다.
- ifstream: file 읽기
- ofstream: file에 쓰기
- fstream: file 읽고 쓰기
cin,cout 연산자 모두 사용 가능
fstream만의 파일관련 연산들
fstream fstrm; file과 바인딩되지 않은 파일 스트림 생성
fstream fstrm(s); fstream 만들어 파일 s를 열기 fstream fstrm(s, mode) mode를 넣고 파일 열기 fstrm.open(s) 파일s를 열고 fstrm과 바인딩 fstrm.open(s, mode) mode 추가 fstrm.close() fstrm 닫기 fstrm.is_open() fstrm과 연관된 file이 열려있는지 유무 리턴 - fstream fstrm(s)와 fstrm open(s)의 차이?
- -> 모두 파일을 여는 작업인건 같다.
- -> fstrm open(s)는 이전에 생성한 fstream을 이용해 파일 open은 이후에 필요할 때 하는 것이고,
- -> 차이는 fstream fstrm(s)는 fstream을 생성함과 동시에 파일을 여는 것이고,
- -> 같은 fstream을 여러번 사용해서 open할 수 있다.
IO 클래스들도 모두 상속관계에 있는 클래스들이기 때문에, 상위 클래스의 참조자로 하위 클래스들을 받을 수 있다.
open and close Members
ifstream in(ifile); //in은 그저 변수명일 뿐이다. ifstream 생성과 동시에 ifile 파일을 여는 코드. ofstream out; out.open(ifile + ".copy"); in.close(); in.open(ifile + "2"); // 다른 파일을 열기 전에 close()를 시켜주어야 한다.
잘 열렸으면 goodbit 세팅됨 → good() = true
실패했으면 fail() → true
Automatic Construction and Destruction
for (auto p = argv + 1; p != argv + argc; ++p) { ifstream input(*p); if (input) { process(input); } else cerr << "couldn't open: " + string(*p); }
ifstream 객체인 input은 매 루프를 수행할 때마다 생성되고 파괴된다
파괴시, 해당 스트림과 바인딩된 파일도 자동으로 close된다.
for 루프 내부에서 **ifstream**을 정의하고 사용하는 것이 리소스 관리에 더 편리한 이유는 자동으로 리소스를 관리해주기 때문입니다. C++에서 객체의 범위를 벗어나면 해당 객체의 소멸자(destructor)가 호출됩니다. 이것은 RAII(Resource Acquisition Is Initialization) 원칙에 기반하고 있습니다.
8.2.2 File Modes
파일을 열 때 어떻게 열어야 하는지 mode
in open for input
out open for output app seek to the end before every write ate seek to the end immediately after the open trunc truncate the file binary do IO operations in binary mode out mode로 파일 열면 implicit truncate이라서 기존 파일 empy처리한다.
ofstream은 default mode가 out이다 → 열면 파일 empty됨
→ 파일 내용 보존하는 유일한 방법: app, in) mode 세팅
파일 모드는 파일을 열 때마다(open) 결정된다
8.3 string Streams
stringstream ⇒ istringstream + ostringstream
sstream strm strm 스트림 생성
sstream strm(s) string s의 복사본을 strm 스트림이 갖는다 strm.str() strm 스트림이 갖고 있는 string을 복사해서 리턴한다 strm.str(s) string s의 복사본을 strm 스트링이 갖는다. istringstream 사용법
struct PersonInfo { string name; vector<string> phones; }; string line, word; vector<PersonInfo> people; while (getline(cin, line)) { PersonInfo info; istringstream record(info); record >> info.name; while (record >> word) { info.phones.push_back(word); } people.push_back(info); }
ostringstream 사용법
output은 만들어내야 하지만 당장 출력할 필요는 없을 때 사용하면 좋다.
for (const auto &entry : people) { ostringstream formatted, badnums; for (const auto &nums : entry.phones) { if (!valid(nums)) { badnums << " " << nums; } else { formatted << " " << format(nums); } } if (badnums.str().empty()) { os << entry.name << " " << formatted.str() << endl; } else { cerr << "input error: " << entry.name << " invalid numbers(s) " << badnums.str() << endl; } }
'c++' 카테고리의 다른 글
C++ Primer CH10. Generic Algorithms (0) 2024.01.21 C++ Primer CH9. Sequential Containers (1) 2024.01.21 C++ Primer CH7. Classes (0) 2024.01.21 C++ Primer CH6. Functions (0) 2024.01.21 C++ Primer CH4. Expressions (0) 2024.01.21