파일 종류

 

파일은 텍스트 파일과 바이너리 파일로 나뉜다. 텍스트 파일은 문자 데이터로 구성된 파일로, 사람들이 사용하는 글자 혹은 문자들만 포함된다. 각 문자는 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;
}

 

애스터로이드