파일 종류
파일은 텍스트 파일과 바이너리 파일로 나뉜다. 텍스트 파일은 문자 데이터로 구성된 파일로, 사람들이 사용하는 글자 혹은 문자들만 포함된다. 각 문자는 ASCII 코드나 유니코드로 저장되며, 일반적으로 텍스트 편집기를 사용해 읽고 수정할 수 있고, 대표적인 예로 txt 파일이 있다. 반면, 바이너리 파일은 텍스트로 표현되지 않는 바이너리 데이터를 포함하며, 특정 프로그램만이 이 데이터를 해석할 수 있고, 이미지, 오디오, 실행 파일 등이 바이너리 파일의 대표적 예이다. 바이너리 파일은 각 바이트의 의미가 응용 프로그램에 의해 정의된다.
참고로 어느 파일이든 파일의 끝을 읽으면 EOF
, 즉 -1을 반환한다.
파일 입출력 스트림 (File I/O Stream)
파일 입출력 스트림은 파일을 프로그램과 연결한다. 이를 사용하기 위해서는 아래와 같이 fstream
을 추가해주어야 한다.
#include <fstream>
using namespace std;
ofstream
ofstream
의 스트림 객체를 만들어서 이를 활용하여 파일을 쓸 수 있다.
ofstream fout;
fout.open("filepath\\text.txt");
if (not fout) {
cout << "Failed to open file" << endl;
}
fout << ...
fout.close();
위와 같이 open
메소드를 이용하여 파일을 열 수 있다. 만약 정상적으로 열리지 않았다면 스트림 객체는 NULL
을 가리키므로 검사하여 파일이 정상적으로 열렸는지 확인해야 한다. 만약 파일이 정상적으로 열렸다면 <<
연산자를 이용하여 파일에 쓸 수 있다. endl
등 조작자를 사용할 수 있다. 파일 쓰기가 끝났다면 close
메소드를 이용하여 파일을 닫아야 한다.
ifstream
ifstream
의 스트림 객체를 만들어서 이를 활용하여 파일을 읽을 수 있다.
ifstream fin;
fin.open("filepath\\text.txt");
if (not fin) {
cout << "Failed to open file" << endl;
}
fin >> ...
fin.close();
위와 같이 open
메소드를 이용하여 파일을 열 수 있다. 만약 정상적으로 열리지 않았다면 스트림 객체는 NULL
을 가리키므로 검사하여 파일이 정상적으로 열렸는지 확인해야 한다. 만약 파일이 정상적으로 열렸다면 >>
연산자를 이용하여 파일을 읽을 수 있다. 파일 읽기가 끝났다면 close
메소드를 이용하여 파일을 닫아야 한다.
fstream
fstream
의 스트림 객체를 만들어서 이를 활용하여 파일을 읽고 쓸 수 있다. 쓰기만 지원하는 ofstream
과 읽기만 지원하는 ifsream
과 달리 읽기와 쓰기 모두 지원한다. 단 파일 모드를 통해 읽기 혹은 쓰기 혹은 읽고 쓰기를 명시하여야 한다.
파일 모드 (File Mode)
파일 모드(file mode)란 파일 입출력에 대한 구체적 작업 형태를 지정하는 것이다.
파일 모드 | 의미 |
ios::in |
읽기 모드 |
ios::out |
쓰기 모드 |
ios::ate |
열기 후 파일 포인터를 파일 끝으로 설정 파일 포인터를 옮겨 해당 위치부터 쓰기 가능 |
ios::app |
파일 쓰기 시에만 적용 가능 자동으로 파일 포인터가 파일 끝으로 설정 |
ios::trunc |
ios::out 모드 지정시 디폴트로 함께 지정파일이 존재하면 내용을 모두 지어 파일 크기를 0으로 만듦 |
ios::binary |
바이너리 I/O로 설정하여 파일 열기 설정되지 않는다면 디폴트로는 텍스트 I/O |
파일 모드는 파일을 열 때 지정할 수 있다.
void open(const char* filename, ios::openmode mode);
아래와 같이 파일 모드를 여러개도 적용할 수 있다.
fstream fio;
fio.open("temp.txt", ios::out | ios::in | ios::ate);
텍스트 파일 (Text File)
텍스트 파일이라면 iostream
의 멤버 함수(참고 링크)를 그대로 사용하면 된다.
바이너리 파일에서의 쓰기와 달리 단락을 바꿀 때 \n
을 처리해야 하는데, 운영체제마다 다르긴 하지만 윈도우의 경우 \n
이 자동으로 \r\n
으로 변환되어 저장된다.
바이너리 파일 (Binary File)
파일 스트림을 바이너리 모드로 지정하고 파일을 열어주고 파일을 읽고 쓰면 된다.
바이트 단위로 파일을 읽고 쓸 때는 입출력 스트림의 get()
, put()
멤버 함수를 사용하면 된다.
그러나 만약 블록 단위로 파일을 입력 혹은 출력하고 싶다면 아래와 같은 멤버 함수를 사용하면 된다.
// 파일에서 최대 n개의 바이트를 배열 s에 읽는데 파일의 끝을 만나면 중단
istream& read(char* s, int n)
// 배열 s에 있는 처음 n개의 바이트를 파일에 저장
ostream& write(char* s, int n)
// 최근 파일에서 읽은 바이트 수 반환
int gcount()
스트림 상태
스트림 상태를 나타내는 비트 정보 | |
비트 | 의미 |
eofbit |
파일의 끝을 만났을 때 -1로 설정 |
failbit |
포맷 오류나 쓰기 금지된 곳에서 쓰기 실행 들에 대한 전반적인 I/O 실패 시 1로 설정 |
badbit |
스트림이나 데이터가 손상되는 수준의 진단되지 않은 문제가 발생하거나 유효하지 않은 입출력 명령이 주어졌을 경우 1로 설정 |
스트림 상태를 검사하는 멤버 함수 | |
멤버 함수 | 의미 |
eof() |
eofbit 라면 true 반환 |
fail() |
failbit 혹은 badbit 라면 true 반환 |
bad() |
badbit 라면 true 반환 |
good() |
스트림이 정상적일 때 true 반환 |
clear() |
스트림 상태 변수를 0으로 지움 |
파일 포인터 (File Pointer)
순차 접근은 읽은 다음 위치에서 읽고, 쓴 다음 위치에 쓰는 방식으로 기본적인 파일 입출력 방식이다. 임의 접근은 파일 내의 임의의 위치로 옮겨 다니면서 읽고 쓰는 방식이다. 이때 파일 포인터가 사용된다.
파일 포인터는 파일에서 다음에 읽거나 쓸 위치를 표시하는 마크로 기본적으로 C++에서는 파일을 열 때 두 개의 포인터를 유지한다. 하나는 읽을 위치를 표기하는 get pointer 이고, 하나는 쓸 위치를 표기하는 put pointer 이다.
파일 모드를 ios::in
으로 열면 get pointer가 파일의 시작에 위치한다. ios::out
으로 열면 put pointer가 파일의 시작에 위치한다. 만약 ios::ate
로 열면 put pointer가 파일의 끝에 위치한다. ios::app
으로 열면 put pointer가 파일의 앞에 위치하고, put pointer는 쓸 때 마다 자동으로 파일의 끝에 위치한다.
파일 포인터는 다음과 같은 함수로 임의 접근이 가능하다.
// 정수 값으로 주어진 절대 위치 pos로 get pointer 이동
istream& seekg(streampos pos)
// seekbase를 기준으로 offset 만큼 떨어진 위치로 get pointer 이동
istream& seekg(streamoff offset, ios::seekdir seekbase)
// 정수 값으로 주어진 절대 위치 pos로 put pointer 이동
ostream& seekp(streampos pos)
// seekbase를 기준으로 offset 만큼 떨어진 위치로 put pointer 이동
ostream& seekp(streamoff offset, ios::seekdir seekbase)
// 입력 스트림의 현재 get pointer 반환
streampos tellg()
// 출력 스트림의 현재 put pointer 반환
streampos tellp()
참고로 seekbase는 다음과 같다.
seekbase | 의미 |
ios::beg |
파일 처음 위치를 기준으로 파일 포인터 이동 |
ios::cur |
현재 파일 포인터 위치를 기준으로 파일 포인터 이동 |
ios::end |
파일 끝 위치(EOF )를 기준으로 파일 포인터 이동 |
간단하게 파일 포인터를 이용하여 아래와 같이 파일의 크기를 구하는 함수를 만들 수 있다.
long long getFileSize(ifstream& fin) {
fin.seekg(0, ios::end);
long long length = fin.tellg();
return length;
}
'Language > C & C++' 카테고리의 다른 글
[ C++] 예외 처리(exception handling) (0) | 2024.12.06 |
---|---|
[C++] 포맷 플래그(format flag) 및 조작자(manipulator) (0) | 2024.12.04 |
[C++] 입출력 스트림(I/O stream) 및 버퍼(buffer) (0) | 2024.12.04 |
[C++] 람다(lambda) 표현식 (0) | 2024.11.15 |
[C++] auto 키워드 (0) | 2024.11.14 |