본문 바로가기

Programming/C&CPP

C++ fstream 객체를 통한 파일 입출력

반응형

C++ 프로그래밍을 하다 보면 파일을 자주 다루게 됩니다.

필요한 데이터를 바이너리에 모두 넣지 않고 별도의 파일로 분리해서 읽어올 수 있습니다.

C++은 파일 입출력을 지원하기 위한 ifstream, ofstream 클래스를 제공합니다.

파일 입출력을 처리하는 방법을 알아보겠습니다.

 

1. 파일 생성 및 열기

C++의 ifstream이나 ofstream을 사용하려면 <fstream> 헤더를 추가해야 합니다.

#include <fstream>

ofstream은 파일에 기록할 때 사용하고 ifstream은 파일에 저장된 데이터를 읽어올 때 사용합니다.

입력과 출력이 모두 가능한 fstream 클래스 역시 존재합니다.

클래스의 open() 메소드를 통해 파일을 열거나 생성할 수 있습니다.

std::ofstream ofs;
ofs.open("파일 경로");

std::ifstream ifs;
ifs.open("파일 경로");

생성자에 파일 경로를 입력해서 바로 파일을 생성하거나 여는 것도 가능합니다.

std::ofstream ofs("파일 경로");
std::ifstream ifs("파일 경로");

다음과 같이 파일을 생성하거나 여는 코드를 작성할 수 있습니다.

#include <fstream>
#include <iostream>
#include <string>

int main()
{
	std::ofstream ofs("D:\\test.txt", std::ios::out | std::ios::app);
	if (ofs.fail())
	{
		std::cerr << "Error!" << std::endl;
	}

	std::ifstream ifs;
	ifs.open("D:\\test.txt", std::ios::in);
	if (!ifs)
	{
		std::cerr << "Error!" << std::endl;
	}
	return 0;
}

ofstream 객체(ofs)는 생성자를 통해 파일을 생성했고 ifstream 객체(ifs)는 open() 메소드를 사용했습니다.

파일을 열 때 모드를 설정할 수 있는데 지원하는 모드들은 다음과 같습니다.

in

파일을 읽기 모드로 열기 (ifstream에서 기본값)

out

파일을 쓰기 모드로 열기 (ofstream에서 기본값)

binary

텍스트 모드 대신 바이너리 모드로 열기

ate

출력 위치가 파일의 끝에서 시작

app

모든 출력이 파일의 끝에 추가 됨

trunc

파일의 내용을 모두 삭제하고 열기

원하는 파일 처리를 위해 OR 연산자(|)로 결합해서 파일을 열 때 사용하면 됩니다.

파일이 정상적으로 열렸는지 확인하려면 fail()이나 bad() 함수 등을 호출하면 됩니다.

C++11 이후부터는 fstream이 bool 타입 변환 메소드를 지원하기 때문에 객체 자체를 조건문에 넣어도 됩니다.

 

2. 파일 닫기

파일을 닫을 때는 close()를 호출하면 됩니다.

fstream 객체는 RAII 패턴이 적용되어 있기 때문에 객체가 소멸될 때 자동으로 닫힙니다.

ofs.close();
ifs.close();

명시적으로 파일을 닫고 싶은 경우에 close()를 호출하면 됩니다.

 

3. 파일에 데이터 쓰기 (<< 연산자)

파일에 데이터를 기록할 때는 cout과 동일하게 << 연산자를 사용할 수 있습니다.

#include <fstream>
#include <iostream>
#include <string>

int main()
{
	std::ofstream ofs("D:\\test.txt");
	if (ofs.fail())
	{
		std::cerr << "Error!" << std::endl;
		return -1;
	}
	ofs << "Hello World!" << std::endl;
	ofs << 1234 << std::endl;
	ofs << 'a' << std::endl;
	
	return 0;
}

문자열은 물론이고 정수형 등의 다양한 타입을 파일에 쓸 수 있습니다.

파일 쓰기 결과

<< 연산자 외에 put() 메소드로 char 타입을 파일에 기록할 수 있습니다.

다만 put() 메소드는 char 타입만 쓸 수 있기 때문에 자주 사용되지는 않습니다.

 

4. 파일에서 데이터 읽기

파일에서 데이터를 읽을 때는 getline() 메소드를 사용할 수 있습니다.

#include <fstream>
#include <iostream>
#include <string>

int main()
{
	std::ifstream ifs("D:\\test.txt");
	if (ifs.fail())
	{
		std::cerr << "Error!" << std::endl;
		return -1;
	}

	char line[256] = { 0, };
	while (ifs.getline(line, 256)) {
		std::cout << line << std::endl;
	}

	return 0;
}

먼저 충분한 크기의 버퍼를 생성한 후에 getline()에 전달하면 됩니다.

다만 이 경우 라인보다 작은 크기의 버퍼를 설정하면 읽기가 중단됩니다.

이 때는 put() 메소드와 대응되는 get() 메소드를 활용해서 각각의 char를 읽어올 수 있습니다.

	char c;
	while (ifs.get(c)) {
		std::cout << c;
	}

다음과 같이 파일의 내용이 화면에 출력됩니다.

파일 읽기 결과

파일의 내용이 공백으로 구분되고 타입이 정해진 파일을 읽을 때는 >> 연산자를 사용할 수 있습니다.

1 2 3 4 5
5 6 7 8 10

다음과 같이 >> 연산자를 사용할 수 있습니다.

#include <fstream>
#include <iostream>
#include <string>

int main()
{
	std::ifstream ifs("D:\\test.txt");
	if (ifs.fail())
	{
		std::cerr << "Error!" << std::endl;
		return -1;
	}

	while (!ifs.eof()) {
		int a;
		ifs >> a;
		std::cout << a << std::endl;
	}

	return 0;
}

문자열로 읽는 대신 바로 int 타입으로 읽을 수 있습니다.

 

파일 입출력은 프로그램의 규모가 어느 정도 커지면 필수적으로 사용됩니다.

위 예제를 통해 기본적인 C++의 파일 입출력을 적용하는 것이 가능합니다.

반응형