빠른 흐름
cpp
#include <fstream>
#include <sstream>
#include <string>
// 파일 읽기 — 줄 단위
std::ifstream file("scores.txt");
std::string line;
while (std::getline(file, line)) {
std::stringstream ss(line);
std::string name; int score;
ss >> name >> score;
std::cout << name << ": " << score << "\n";
}
// 파일 쓰기
std::ofstream out("result.txt");
out << "Alice: 95\n";기본 흐름
ifstream / ofstream / fstream — 파일 방향 선택
C++ 스트림은 cin/cout과 같은 인터페이스를 파일에 적용합니다. 파일 열기 성공 여부는 반드시 확인해야 합니다.
cpp
// 읽기 전용
std::ifstream in("data.txt");
if (!in) throw std::runtime_error("파일 열기 실패: data.txt");
// 쓰기 전용 (기본: 덮어쓰기)
std::ofstream out("output.txt");
out << "결과: " << 42 << "\n";
// 추가 쓰기 모드
std::ofstream append("log.txt", std::ios::app);
append << "새 항목\n";
// 읽기/쓰기 모두
std::fstream rw("data.txt", std::ios::in | std::ios::out);스트림 상태 — 읽기 실패를 조용히 넘기지 않기
스트림 연산이 실패해도 예외를 던지지 않습니다. 상태를 확인하지 않으면 잘못된 값으로 조용히 진행됩니다.
cpp
std::ifstream file("data.txt");
// ❌ 상태 확인 없이 읽기
int value;
file >> value; // 파일 없어도 실패 없이 통과
std::cout << value; // 쓰레기 값 출력
// ✅ 파일 열기 성공 확인
if (!file.is_open()) {
std::cerr << "파일 열기 실패\n";
return;
}
// ✅ 읽기 성공 확인
while (file >> value) { // 읽기 실패 시 루프 종료
process(value);
}
// 스트림 상태 확인
file.good() // 모든 비트 정상
file.eof() // 파일 끝 도달
file.fail() // 논리적 오류 (형식 불일치 등)
file.bad() // 물리적 오류 (읽기 실패 등)바이너리 모드 — ios::binary
텍스트 모드에서는 플랫폼마다 줄바꿈 변환(\r\n ↔ \n)이 일어납니다. 이미지, 바이너리 파일은 ios::binary를 지정해야 합니다.
cpp
// 바이너리 쓰기
std::ofstream out("data.bin", std::ios::binary);
int values[] = {1, 2, 3, 4, 5};
out.write(reinterpret_cast<const char*>(values), sizeof(values));
// 바이너리 읽기
std::ifstream in("data.bin", std::ios::binary);
int read_values[5];
in.read(reinterpret_cast<char*>(read_values), sizeof(read_values));
std::cout << in.gcount() << " bytes read\n"; // gcount: 실제 읽은 바이트 수seek / tell — 파일 위치 직접 제어
cpp
std::fstream f("data.txt", std::ios::in | std::ios::out);
// 현재 위치 저장
std::streampos pos = f.tellg(); // 읽기 위치 (tellp: 쓰기 위치)
// 위치 이동
f.seekg(0, std::ios::beg); // 파일 시작으로
f.seekg(0, std::ios::end); // 파일 끝으로
f.seekg(-10, std::ios::cur); // 현재에서 10바이트 뒤로
// 파일 크기 계산 (끝 - 시작)
f.seekg(0, std::ios::end);
std::streamsize size = f.tellg();
f.seekg(0, std::ios::beg); // 다시 시작으로
// 특정 위치로 복귀
f.seekg(pos);stringstream — 문자열 파싱과 조립
stringstream은 문자열을 스트림처럼 읽거나 씁니다. CSV/TSV 파싱, 여러 값의 문자열 조립에 유용합니다.
cpp
// 문자열 파싱 — 공백/탭으로 구분된 필드 분리
std::string line = "Alice 95 true";
std::stringstream ss(line);
std::string name; int score; bool pass;
ss >> name >> score >> pass;
// 여러 값을 문자열로 조립
std::ostringstream oss;
oss << "User: " << name << ", Score: " << score;
std::string result = oss.str(); // "User: Alice, Score: 95"
// CSV 파싱 — getline으로 구분자 기준 분리
std::string csv = "1,Alice,95";
std::stringstream csv_ss(csv);
std::string token;
while (std::getline(csv_ss, token, ',')) {
std::cout << token << "\n"; // "1", "Alice", "95"
}체크포인트
| 상황 | 적합한 선택 |
|---|---|
| 파일 읽기 | std::ifstream |
| 파일 쓰기 (덮어쓰기) | std::ofstream |
| 파일 추가 쓰기 | std::ofstream(path, ios::app) |
| 바이너리 파일 읽기/쓰기 | ios::binary 플래그 추가 |
| 원시 바이트 읽기/쓰기 | read(buf, n) / write(buf, n) |
| 파일 위치 이동 | seekg(offset, ios::beg/cur/end) |
| 현재 위치 조회 | tellg() (읽기) / tellp() (쓰기) |
| 문자열 파싱 (공백 구분) | std::stringstream ss(line); ss >> a >> b |
| 문자열 파싱 (다른 구분자) | getline(ss, token, ',') |
| 값들을 문자열로 조립 | std::ostringstream |
주의할 점
파일이 없거나 형식이 틀려도 스트림은 예외를 던지지 않습니다. 상태를 확인하지 않으면 잘못된 값이 조용히 사용됩니다.
cpp
// ❌ 상태 확인 없이 사용 — 파일 없어도 오류 없이 통과
std::ifstream f("missing.txt");
int n;
f >> n; // 실패 — n은 초기화 안 된 값
std::cout << n; // 쓰레기 값 출력
// ✅ 열기 확인
std::ifstream f("data.txt");
if (!f) {
std::cerr << "파일 열기 실패\n";
return 1;
}
// ❌ stringstream 재사용 시 상태 초기화 빠뜨림
std::stringstream ss;
ss << "42"; int a; ss >> a;
ss << "99"; int b; ss >> b; // ❌ fail 비트가 남아 읽기 실패
// ✅ 재사용 전 clear() + str() 초기화
ss.clear();
ss.str("99");
ss >> b; // ✅ 99참고 링크
2 sources