C++ 스트림 I/O | "iostream" 완벽 가이드
이 글의 핵심
C++ 스트림 I/O에 대해 정리한 개발 블로그 글입니다. #include <iostream> using namespace std;
기본 입출력
#include <iostream>
using namespace std;
int main() {
// 출력
cout << "Hello World" << endl;
// 입력
int x;
cin >> x;
cout << "입력: " << x << endl;
// 여러 값
int a, b;
cin >> a >> b;
cout << a + b << endl;
}
포매팅
#include <iomanip>
int main() {
double pi = 3.14159265359;
// 소수점 자릿수
cout << fixed << setprecision(2) << pi << endl; // 3.14
// 너비
cout << setw(10) << 42 << endl; // " 42"
// 채우기
cout << setfill('0') << setw(5) << 42 << endl; // "00042"
// 16진수
cout << hex << 255 << endl; // ff
// 8진수
cout << oct << 64 << endl; // 100
// 10진수
cout << dec << 100 << endl; // 100
}
stringstream
#include <sstream>
int main() {
// 문자열 → 숫자
string s = "123 456 789";
istringstream iss(s);
int a, b, c;
iss >> a >> b >> c;
cout << a + b + c << endl; // 1368
// 숫자 → 문자열
ostringstream oss;
oss << "값: " << 42 << ", " << 3.14;
cout << oss.str() << endl; // "값: 42, 3.14"
}
실전 예시
예시 1: CSV 파싱
#include <sstream>
#include <vector>
vector<vector<string>> parseCSV(const string& csv) {
vector<vector<string>> result;
istringstream iss(csv);
string line;
while (getline(iss, line)) {
vector<string> row;
istringstream lineStream(line);
string cell;
while (getline(lineStream, cell, ',')) {
row.push_back(cell);
}
result.push_back(row);
}
return result;
}
int main() {
string csv = "Alice,25,90\nBob,30,85\nCharlie,35,95";
auto data = parseCSV(csv);
for (const auto& row : data) {
for (const auto& cell : row) {
cout << cell << "\t";
}
cout << endl;
}
}
예시 2: 로그 포매터
#include <sstream>
#include <iomanip>
class Logger {
public:
template<typename... Args>
void log(Args... args) {
ostringstream oss;
// 타임스탬프
auto now = chrono::system_clock::now();
auto time = chrono::system_clock::to_time_t(now);
oss << "[" << put_time(localtime(&time), "%Y-%m-%d %H:%M:%S") << "] ";
// 메시지
(oss << ... << args);
cout << oss.str() << endl;
}
};
int main() {
Logger logger;
logger.log("서버 시작");
logger.log("포트: ", 8080);
logger.log("사용자 ", "Alice", " 로그인");
}
예시 3: 테이블 출력
void printTable(const vector<vector<string>>& data) {
// 열 너비 계산
vector<size_t> widths(data[0].size(), 0);
for (const auto& row : data) {
for (size_t i = 0; i < row.size(); i++) {
widths[i] = max(widths[i], row[i].size());
}
}
// 출력
for (const auto& row : data) {
for (size_t i = 0; i < row.size(); i++) {
cout << left << setw(widths[i] + 2) << row[i];
}
cout << endl;
}
}
int main() {
vector<vector<string>> data = {
{"Name", "Age", "Score"},
{"Alice", "25", "90"},
{"Bob", "30", "85"},
{"Charlie", "35", "95"}
};
printTable(data);
}
예시 4: 설정 파일 파싱
#include <fstream>
#include <map>
map<string, string> loadConfig(const string& filename) {
map<string, string> config;
ifstream file(filename);
string line;
while (getline(file, line)) {
// 주석 제거
size_t commentPos = line.find('#');
if (commentPos != string::npos) {
line = line.substr(0, commentPos);
}
// 공백 제거
istringstream iss(line);
string key, value;
if (getline(iss, key, '=') && getline(iss, value)) {
config[key] = value;
}
}
return config;
}
int main() {
// config.txt:
// host=localhost
// port=8080
// # 주석
// timeout=30
auto config = loadConfig("config.txt");
for (const auto& [key, value] : config) {
cout << key << " = " << value << endl;
}
}
파일 I/O
#include <fstream>
int main() {
// 쓰기
ofstream out("output.txt");
out << "Hello" << endl;
out << 42 << endl;
out.close();
// 읽기
ifstream in("output.txt");
string line;
while (getline(in, line)) {
cout << line << endl;
}
in.close();
}
조작자
// 정렬
cout << left << setw(10) << "Left" << endl;
cout << right << setw(10) << "Right" << endl;
// 부호
cout << showpos << 42 << endl; // +42
cout << noshowpos << 42 << endl; // 42
// 기수 표시
cout << showbase << hex << 255 << endl; // 0xff
// 불리언
cout << boolalpha << true << endl; // true
cout << noboolalpha << true << endl; // 1
자주 발생하는 문제
문제 1: cin 버퍼
// ❌ 버퍼 남음
int x;
cin >> x;
string line;
getline(cin, line); // 빈 줄 읽음
// ✅ 버퍼 비우기
cin >> x;
cin.ignore();
getline(cin, line);
문제 2: 파일 열기 실패
// ❌ 체크 안함
ifstream file("nonexistent.txt");
string line;
getline(file, line); // 실패
// ✅ 체크
ifstream file("nonexistent.txt");
if (!file.is_open()) {
cerr << "파일 열기 실패" << endl;
return 1;
}
문제 3: 스트림 상태
// 입력 실패 시 스트림 상태 확인
int x;
cin >> x;
if (cin.fail()) {
cout << "입력 실패" << endl;
cin.clear(); // 상태 초기화
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // 버퍼 비우기
}
FAQ
Q1: cout vs printf?
A:
- cout: 타입 안전, C++스러움
- printf: 빠름, C 호환
Q2: endl vs ‘\n’?
A:
- endl: 버퍼 플러시 (느림)
- ‘\n’: 플러시 안함 (빠름)
Q3: stringstream 성능은?
A: 문자열 연결보다 빠를 수 있습니다.
Q4: 바이너리 I/O는?
A: ios::binary 모드 사용.
Q5: 스트림 재사용은?
A: clear()와 str("") 호출.
Q6: iostream 학습 리소스는?
A:
- cppreference.com
- “The C++ Standard Library”
- “C++ Primer”
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ Date Parsing & Formatting | “날짜 파싱 및 서식” 가이드
- C++ Designated Initializers | “지정 초기화” 가이드
- C++ Locale | “지역화” 가이드
관련 글
- C++ 시리즈 전체 보기
- C++ Adapter Pattern 완벽 가이드 | 인터페이스 변환과 호환성
- C++ ADL |
- C++ Aggregate Initialization |