C++ 입출력 라이브러리 완벽 가이드
개요
C++의 입출력 시스템은 iostream 라이브러리를 중심으로 구성되며, 타입 안전하고 확장 가능한 스트림 기반 I/O를 제공합니다.
목차
기본 입출력
iostream 기본 객체
#include <iostream>
using namespace std;
// 표준 입출력 객체
cin // 표준 입력
cout // 표준 출력
cerr // 표준 오류 (버퍼링 안됨)
clog // 표준 로그 (버퍼링 됨)
기본 출력 (cout)
#include <iostream>
// 기본 출력
cout << "Hello World!" << endl;
cout << "Number: " << 42 << "\n";
// 연쇄 출력
cout << "Name: " << name << ", Age: " << age << endl;
// 다양한 타입 출력
int num = 100;
double pi = 3.14159;
char grade = 'A';
string text = "Hello";
cout << num << " " << pi << " " << grade << " " << text << endl;
// endl vs '\n'
cout << "Line 1" << endl; // 개행 + 버퍼 플러시
cout << "Line 2\n"; // 개행만 (더 빠름)
기본 입력 (cin)
#include <iostream>
#include <string>
// 기본 입력
int number;
cin >> number;
string word;
cin >> word; // 공백까지만 읽음
// 여러 값 입력
int a, b, c;
cin >> a >> b >> c;
// 전체 줄 입력
string line;
getline(cin, line); // 전체 줄 읽기
getline(cin, line, ','); // 특정 구분자까지 읽기
// 입력 버퍼 비우기
cin.ignore(); // 1문자 무시
cin.ignore(1000, '\n'); // 개행까지 무시
고급 입력 기법
#include <iostream>
#include <limits>
// 안전한 입력
int safe_input() {
int value;
while (!(cin >> value)) {
cout << "Invalid input. Try again: ";
cin.clear(); // 오류 플래그 제거
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
return value;
}
// 문자 단위 입력
char ch;
ch = cin.get(); // 1문자 읽기 (공백, 개행 포함)
cin.get(ch); // 참조로 읽기
cin.putback(ch); // 문자 되돌리기
cin.peek(); // 다음 문자 확인 (읽지 않음)
// 블록 입력
char buffer[100];
cin.read(buffer, 99); // 최대 99문자 읽기
streamsize bytes_read = cin.gcount(); // 실제 읽은 바이트 수
파일 입출력
ifstream (파일 읽기)
#include <fstream>
#include <iostream>
#include <string>
// 파일 열기
ifstream file("input.txt");
ifstream file("input.txt", ios::in); // 명시적 읽기 모드
// 열기 확인
if (!file.is_open()) {
cerr << "파일을 열 수 없습니다!" << endl;
return -1;
}
// 다양한 읽기 방법
string line;
while (getline(file, line)) { // 줄 단위 읽기
cout << line << endl;
}
// 단어 단위 읽기
string word;
while (file >> word) {
cout << word << " ";
}
// 전체 파일 읽기
string content((istreambuf_iterator<char>(file)),
istreambuf_iterator<char>());
file.close(); // 자동으로 소멸자에서 호출되지만 명시적 호출 권장
ofstream (파일 쓰기)
#include <fstream>
// 파일 쓰기 (덮어쓰기)
ofstream file("output.txt");
ofstream file("output.txt", ios::out);
// 파일 쓰기 (추가 모드)
ofstream file("output.txt", ios::app);
// 쓰기
file << "Hello World!" << endl;
file << "Number: " << 42 << endl;
// 서식 적용
file << fixed << setprecision(2) << 3.14159 << endl;
file.close();
fstream (읽기/쓰기)
#include <fstream>
// 읽기/쓰기 모드
fstream file("data.txt", ios::in | ios::out);
// 파일이 없으면 생성
fstream file("data.txt", ios::in | ios::out | ios::app);
// 파일 포인터 조작
file.seekg(0, ios::beg); // 읽기 포인터를 처음으로
file.seekp(0, ios::end); // 쓰기 포인터를 끝으로
streampos pos = file.tellg(); // 현재 읽기 포인터 위치
파일 모드
ios::in // 읽기
ios::out // 쓰기
ios::app // 추가 (파일 끝에서 쓰기)
ios::ate // 파일 끝으로 이동
ios::trunc // 파일 내용 삭제
ios::binary // 바이너리 모드
// 조합 사용
ofstream file("data.txt", ios::out | ios::app);
ifstream file("data.bin", ios::in | ios::binary);
바이너리 파일 처리
#include <fstream>
struct Person {
char name[50];
int age;
double salary;
};
// 바이너리 쓰기
ofstream file("person.dat", ios::binary);
Person p = {"John Doe", 30, 50000.0};
file.write(reinterpret_cast<const char*>(&p), sizeof(Person));
// 바이너리 읽기
ifstream file("person.dat", ios::binary);
Person p;
file.read(reinterpret_cast<char*>(&p), sizeof(Person));
문자열 스트림
istringstream (문자열에서 읽기)
#include <sstream>
string data = "123 45.6 Hello";
istringstream iss(data);
int num;
double d;
string word;
iss >> num >> d >> word;
cout << num << ", " << d << ", " << word << endl;
// 줄 단위 파싱
string line = "apple,banana,cherry";
istringstream iss(line);
string item;
vector<string> tokens;
while (getline(iss, item, ',')) {
tokens.push_back(item);
}
ostringstream (문자열로 출력)
#include <sstream>
ostringstream oss;
oss << "Number: " << 42 << ", Pi: " << 3.14159;
string result = oss.str();
cout << result << endl;
// 문자열 포맷팅
string format_number(int num, double value) {
ostringstream oss;
oss << "ID: " << setfill('0') << setw(5) << num
<< ", Value: " << fixed << setprecision(2) << value;
return oss.str();
}
stringstream (읽기/쓰기)
#include <sstream>
stringstream ss;
ss << "Hello " << 123;
ss << " World";
string result = ss.str(); // "Hello 123 World"
// 내용 변경
ss.str("New content");
ss.clear(); // 스트림 상태 플래그 초기화
서식 지정
iomanip 헤더
#include <iomanip>
// 폭 지정
cout << setw(10) << "Hello" << endl; // 우측 정렬
cout << left << setw(10) << "Hello" << endl; // 좌측 정렬
cout << setfill('*') << setw(10) << 123 << endl; // 빈 공간 채우기
// 정밀도
cout << setprecision(3) << 3.14159 << endl; // 3.14
cout << fixed << setprecision(2) << 3.14159 << endl; // 3.14
cout << scientific << 3.14159 << endl; // 3.141590e+00
// 진법
cout << hex << 255 << endl; // ff
cout << oct << 255 << endl; // 377
cout << dec << 255 << endl; // 255
// 불린값
cout << boolalpha << true << endl; // true
cout << noboolalpha << true << endl; // 1
플래그 직접 조작
// 현재 플래그 저장
ios_base::fmtflags old_flags = cout.flags();
// 플래그 설정
cout.setf(ios::fixed | ios::showpoint);
cout.precision(2);
cout << 3.14159 << endl; // 3.14
// 플래그 복원
cout.flags(old_flags);
// 특정 플래그만 해제
cout.unsetf(ios::fixed);
커스텀 조작자
// 간단한 조작자
ostream& tab(ostream& os) {
return os << '\t';
}
cout << "Name" << tab << "Age" << tab << "Score" << endl;
// 매개변수가 있는 조작자
struct setcolor {
string color;
setcolor(const string& c) : color(c) {}
};
ostream& operator<<(ostream& os, const setcolor& sc) {
// ANSI 색상 코드 (예시)
if (sc.color == "red") os << "\033[31m";
else if (sc.color == "green") os << "\033[32m";
else if (sc.color == "reset") os << "\033[0m";
return os;
}
// 사용법
cout << setcolor("red") << "Error!" << setcolor("reset") << endl;
스트림 상태
상태 플래그
#include <iostream>
// 상태 확인
if (cin.good()) // 모든 상태가 정상
if (cin.bad()) // 복구 불가능한 오류
if (cin.fail()) // 복구 가능한 오류 (입력 형식 오류 등)
if (cin.eof()) // 파일 끝
// 상태 초기화
cin.clear(); // 모든 오류 플래그 제거
cin.clear(ios::goodbit); // 특정 상태로 설정
// 상태 설정
cin.setstate(ios::failbit); // fail 상태 설정
오류 처리 예제
int safe_read_int() {
int value;
while (true) {
cout << "Enter an integer: ";
if (cin >> value) {
break; // 성공
} else {
cout << "Invalid input. Try again." << endl;
cin.clear(); // 오류 플래그 제거
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
return value;
}
// 파일 읽기 오류 처리
void read_file(const string& filename) {
ifstream file(filename);
if (!file) {
cerr << "Cannot open file: " << filename << endl;
return;
}
string line;
while (getline(file, line)) {
if (file.bad()) {
cerr << "Read error occurred" << endl;
break;
}
cout << line << endl;
}
if (file.eof()) {
cout << "File read successfully" << endl;
} else if (file.fail()) {
cerr << "Format error occurred" << endl;
}
}
성능 최적화
동기화 해제
#include <iostream>
// C stdio와 동기화 해제 (빠른 입출력)
ios::sync_with_stdio(false);
cin.tie(nullptr);
// 주의: printf/scanf와 혼용 불가
버퍼링 제어
// 출력 버퍼 강제 플러시
cout << "Hello" << flush;
cout << "World" << endl; // 개행 + 플러시
// 입력과 출력 분리
cin.tie(nullptr); // cin과 cout 분리
// 버퍼 크기 설정
char buffer[8192];
cout.rdbuf()->pubsetbuf(buffer, 8192);
빠른 입출력 템플릿
class FastIO {
public:
FastIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
template<typename T>
FastIO& operator>>(T& value) {
cin >> value;
return *this;
}
template<typename T>
FastIO& operator<<(const T& value) {
cout << value;
return *this;
}
FastIO& operator<<(ostream& (*f)(ostream&)) {
cout << f;
return *this;
}
};
FastIO fio;
int n;
fio >> n << "Number: " << n << endl;
실전 예제
1. CSV 파일 파싱
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
struct Record {
string name;
int age;
double salary;
};
vector<Record> parse_csv(const string& filename) {
vector<Record> records;
ifstream file(filename);
string line;
// 헤더 건너뛰기
getline(file, line);
while (getline(file, line)) {
istringstream iss(line);
string token;
Record record;
// Name
getline(iss, record.name, ',');
// Age
getline(iss, token, ',');
record.age = stoi(token);
// Salary
getline(iss, token);
record.salary = stod(token);
records.push_back(record);
}
return records;
}
2. 로그 파일 생성기
#include <iostream>
#include <fstream>
#include <iomanip>
#include <chrono>
#include <ctime>
class Logger {
private:
ofstream logfile;
public:
Logger(const string& filename) : logfile(filename, ios::app) {
if (!logfile.is_open()) {
throw runtime_error("Cannot open log file");
}
}
template<typename... Args>
void log(const string& level, Args&&... args) {
// 현재 시간
auto now = chrono::system_clock::now();
auto time_t = chrono::system_clock::to_time_t(now);
logfile << "[" << put_time(localtime(&time_t), "%Y-%m-%d %H:%M:%S")
<< "] [" << level << "] ";
((logfile << args << " "), ...);
logfile << endl;
logfile.flush();
}
template<typename... Args>
void info(Args&&... args) { log("INFO", args...); }
template<typename... Args>
void error(Args&&... args) { log("ERROR", args...); }
template<typename... Args>
void warning(Args&&... args) { log("WARNING", args...); }
};
// 사용 예
Logger logger("app.log");
logger.info("Application started");
logger.error("Connection failed, code:", 404);
3. 설정 파일 파서
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <string>
class ConfigParser {
private:
map<string, string> config;
public:
bool load(const string& filename) {
ifstream file(filename);
if (!file.is_open()) return false;
string line;
while (getline(file, line)) {
// 주석과 빈 줄 무시
if (line.empty() || line[0] == '#') continue;
// key=value 파싱
size_t pos = line.find('=');
if (pos != string::npos) {
string key = line.substr(0, pos);
string value = line.substr(pos + 1);
// 공백 제거
key.erase(0, key.find_first_not_of(" \t"));
key.erase(key.find_last_not_of(" \t") + 1);
value.erase(0, value.find_first_not_of(" \t"));
value.erase(value.find_last_not_of(" \t") + 1);
config[key] = value;
}
}
return true;
}
string get_string(const string& key, const string& default_value = "") {
auto it = config.find(key);
return (it != config.end()) ? it->second : default_value;
}
int get_int(const string& key, int default_value = 0) {
auto it = config.find(key);
return (it != config.end()) ? stoi(it->second) : default_value;
}
double get_double(const string& key, double default_value = 0.0) {
auto it = config.find(key);
return (it != config.end()) ? stod(it->second) : default_value;
}
bool get_bool(const string& key, bool default_value = false) {
auto it = config.find(key);
if (it == config.end()) return default_value;
string value = it->second;
transform(value.begin(), value.end(), value.begin(), ::tolower);
return (value == "true" || value == "1" || value == "yes");
}
};
4. 진행률 표시기
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
class ProgressBar {
private:
int total;
int current;
int bar_width;
public:
ProgressBar(int total, int width = 50)
: total(total), current(0), bar_width(width) {}
void update(int value) {
current = value;
float progress = (float)current / total;
int pos = bar_width * progress;
cout << "[";
for (int i = 0; i < bar_width; ++i) {
if (i < pos) cout << "=";
else if (i == pos) cout << ">";
else cout << " ";
}
cout << "] " << int(progress * 100.0) << "%\r";
cout.flush();
}
void finish() {
cout << endl;
}
};
// 사용 예
void demo_progress() {
ProgressBar bar(100);
for (int i = 0; i <= 100; ++i) {
bar.update(i);
this_thread::sleep_for(chrono::milliseconds(50));
}
bar.finish();
}
5. 메모리 사용량 모니터
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
class MemoryMonitor {
public:
struct MemInfo {
size_t virtual_memory = 0;
size_t physical_memory = 0;
};
static MemInfo get_memory_usage() {
MemInfo info;
#ifdef _WIN32
// Windows 구현
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
info.virtual_memory = pmc.PagefileUsage;
info.physical_memory = pmc.WorkingSetSize;
}
#else
// Linux 구현
ifstream status("/proc/self/status");
string line;
while (getline(status, line)) {
if (line.substr(0, 6) == "VmSize") {
istringstream iss(line);
string key, unit;
iss >> key >> info.virtual_memory >> unit;
info.virtual_memory *= 1024; // KB to bytes
} else if (line.substr(0, 6) == "VmRSS:") {
istringstream iss(line);
string key, unit;
iss >> key >> info.physical_memory >> unit;
info.physical_memory *= 1024; // KB to bytes
}
}
#endif
return info;
}
static void print_memory_usage() {
auto info = get_memory_usage();
cout << "Memory Usage:" << endl;
cout << " Virtual: " << format_bytes(info.virtual_memory) << endl;
cout << " Physical: " << format_bytes(info.physical_memory) << endl;
}
private:
static string format_bytes(size_t bytes) {
const char* units[] = {"B", "KB", "MB", "GB", "TB"};
int unit = 0;
double size = bytes;
while (size >= 1024 && unit < 4) {
size /= 1024;
unit++;
}
ostringstream oss;
oss << fixed << setprecision(2) << size << " " << units[unit];
return oss.str();
}
};
마지막 업데이트: 2025-06-24