스트림(stream)은 데이터의 흐름을 관리하는 추상적인 개념으로, 프로그램과 외부 장치(파일, 콘솔, 네트워크 등) 간의 데이터를 순차적으로 입출력하는 방식이다. 스트림을 사용하면 데이터를 하나씩 읽거나 쓰는 방식으로 처리할 수 있다.
C++에서는 입력 스트림과 출력 스트림을 통해 데이터를 주고받는 과정을 추상화하여 제공한다. 스트림을 사용하면, 데이터가 어디에서 오고 가는지에 대해 상세하게 신경 쓰지 않고도 입출력 작업을 처리할 수 있다.
1. Stream?
스트림은 데이터가 흘러가는 통로라고 생각할 수 있다. 데이터를 읽거나 쓸 때, 물리적인 장치와 상관없이 일관된 인터페이스를 제공한다.
- 입력 스트림(Input Stream): 데이터를 프로그램으로 가져오는 통로. 예를 들어, 파일이나 콘솔에서 데이터를 읽어오는 작업.
- 출력 스트림(Output Stream): 데이터를 프로그램 밖으로 내보내는 통로. 예를 들어, 콘솔에 출력하거나 파일에 데이터를 쓰는 작업.
2. C++에서의 Stream
C++에서 스트림은 입출력을 추상화한 클래스들로 구성되어 있으며, 표준 라이브러리에서 제공된다.
주요 스트림 클래스들:
- 입력 스트림: std::istream (입력을 위한 스트림 클래스)
- std::cin: 표준 입력(키보드) 스트림
- std::ifstream: 파일 입력을 위한 스트림
- 출력 스트림: std::ostream (출력을 위한 스트림 클래스)
- std::cout: 표준 출력(콘솔) 스트림
- std::ofstream: 파일 출력을 위한 스트림
3. 입출력 스트림(iostream) 사용 예
3.1 표준 입출력 스트림 (cin, cout)
- cin: 사용자로부터 입력을 받을 때 사용
- cout: 콘솔에 출력할 때 사용
#include <iostream>
int main() {
int number;
std::cout << "Enter a number: ";
std::cin >> number;
std::cout << "You entered: " << number << std::endl;
return 0;
}
- std::cin: 표준 입력(키보드)으로부터 데이터를 받는다.
- std::cout: 표준 출력(콘솔)으로 데이터를 출력한다.
- '>>' 연산자: 입력 연산자로 사용되며, cin으로부터 데이터를 변수에 저장한다.
- '<<' 연산자: 출력 연산자로 사용되며, cout으로 데이터를 콘솔에 출력한다.
3.2 파일 입출력 스트림 (ifstream, ofstream)
- 파일에서 입력을 받을 때는 std::ifstream (입력 파일 스트림)
- 파일에 출력을 할 때는 std::ofstream (출력 파일 스트림)
#include <iostream>
#include <fstream>
int main() {
std::ofstream outFile("example.txt");
outFile << "This is an example text." << std::endl;
outFile.close();
std::ifstream inFile("example.txt");
std::string content;
if (inFile.is_open()) {
while (getline(inFile, content)) {
std::cout << content << std::endl;
}
inFile.close();
} else {
std::cout << "Unable to open file" << std::endl;
}
return 0;
}
- std::ifstream: 파일에서 데이터를 읽을 때 사용.
- std::ofstream: 파일에 데이터를 쓸 때 사용.
- getline(): 파일에서 한 줄씩 읽어오는 함수. 입력 스트림에서 데이터를 받아와 문자열 변수에 저장한다.
- open(): 파일을 열고, 데이터 스트림을 연다.
- close(): 사용이 끝난 파일을 닫아 메모리 자원을 해제한다.
4. Stream의 동작 방식
- 스트림은 데이터를 일련의 바이트 흐름으로 처리한다.
- 입출력 장치(키보드, 콘솔, 파일 등)와의 연결을 통해 데이터의 흐름을 관리한다.
- 스트림을 통해 데이터를 순차적으로 처리할 수 있어, 필요한 만큼 데이터를 읽거나 쓸 수 있다.
5. Stream의 장점
- 스트림을 사용하면 입출력 장치에 구애받지 않고 데이터를 처리할 수 있다.
- 키보드, 파일, 네트워크 등의 입출력 장치 간에 일관된 인터페이스를 제공한다.
- 유연한 입출력 관리: 표준 입력과 출력, 파일 입출력을 동일한 방식으로 관리할 수 있다.
- 버퍼링을 통해 데이터를 효율적으로 처리할 수 있다.
6. Stream의 종류
C++에서 제공하는 스트림의 종류는 다양하며, 각각의 목적에 따라 사용된다.
- 표준 스트림
• std::cin: 표준 입력 스트림 (키보드)
• std::cout: 표준 출력 스트림 (콘솔)
• std::cerr: 표준 에러 출력 스트림 (콘솔)
• std::clog: 표준 로그 출력 스트림 (콘솔)
- 파일 스트림
• std::ifstream: 입력 파일 스트림 (파일에서 데이터 읽기)
• std::ofstream: 출력 파일 스트림 (파일에 데이터 쓰기)
• std::fstream: 입력과 출력을 모두 지원하는 파일 스트림
7. Stream의 사용 흐름
스트림을 사용할 때는 일반적으로 다음과 같은 흐름을 따른다:
- 스트림을 열기: 데이터를 입력받을 스트림을 열거나, 데이터를 쓸 스트림을 연다.
- 데이터 읽기/쓰기: 스트림을 통해 데이터를 순차적으로 읽거나 쓴다.
- 스트림 닫기: 스트림 작업이 끝나면 반드시 스트림을 닫아 자원을 해제한다.
8. Buffering과 Stream
- 버퍼링(buffering): 스트림은 일반적으로 데이터를 버퍼에 모아두었다가, 일정량이 쌓이면 한꺼번에 처리한다. 이는 성능을 향상시키는 데 도움을 준다.
- 예를 들어, std::cout은 출력 시 데이터를 즉시 출력하지 않고 버퍼에 모았다가 일정 시점에 출력하는 버퍼링을 적용한다. 이를 통해 입출력 장치 간의 데이터 전송 속도 차이를 줄일 수 있다.
9. Stream의 에러 처리
입출력 과정에서 오류가 발생할 수 있다. 스트림 객체는 상태 플래그를 가지고 있어서, 입출력 중 발생한 오류를 확인할 수 있다.
- fail(): 입력/출력이 실패했을 때 true를 반환.
- eof(): 파일 끝에 도달했을 때 true를 반환.
- bad(): 심각한 오류가 발생했을 때 true를 반환.
std::ifstream file("nonexistent.txt");
if (!file) {
std::cerr << "Error opening file" << std::endl;
}
Summary
- 스트림은 C++에서 데이터를 순차적으로 입력하고 출력하는 통로이다.
- 입력 스트림과 출력 스트림을 통해 키보드, 콘솔, 파일, 네트워크 등의 입출력 장치와 데이터를 주고받는다.
- cin과 cout은 각각 표준 입력과 출력을 위한 스트림이며, 파일 입출력을 위해 ifstream과 ofstream을 사용한다.
- 스트림은 버퍼링을 통해 효율적인 입출력 처리를 지원하며, 에러 처리도 제공한다.