컴공생의 다이어리

[c++] 파일 전체 읽기 본문

Development/C & C++

[c++] 파일 전체 읽기

컴공 K 2021. 1. 3. 19:10

파일 전체를 한 번에 읽기

파일 전체를 한 번에 읽으려면 아래와 같은 코드를 사용하면 된다.

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

int main() {
	// 파일 읽기 준비
	std::ifstream in("test.txt");
	std::string s;
	if (in.is_open()) {
		// 위치 지정자를 파일 끝으로 옮긴다.
		in.seekg(0, std::ios::end);
		// 그리고 그 위치를 읽는다. (파일의 크기)
		int size = in.tellg();
		// 그 크기의 문자열을 할당한다.
		s.resize(size);
		// 위치 지정자를 다시 파일 맨 앞으로 옮긴다.
		in.seekg(0, std::ios::beg);
		// 파일 전체 내용을 읽어서 문자열에 저장한다.
		in.read(&s[0], size);
		std::cout << s << std::endl;
	}
	else {
		std::cout << "파일을 찾을 수 없습니다!" << std::endl;
	}
	return 0;
}

이제 위 코드를 아래에서 자세히 이야기해보자.

 

seekg 함수는 c언에서의 fseek과 같은 함수로, 파일 위치 지정자를 사용자의 편의에 맞게 움직일 수 있다. 두번째 인자는, 파일 내 위치를 의미하고, 첫 번째 인자는 그 위치로부터 얼마나 만큼 떨어져 있느냐를 의미한다. 아래의 코드의 경우 위치 지정자를 파일의 끝에서 0만큼 떨어진 것으로 파일의 끝으로 위치 지정자를 이동시켰다.

// 위치 지정자를 파일 끝으로 옮긴다.
in.seekg(0, std::ios::end);

 

tellg 함수는 위치 지정자의 위치 (시작 지점으로부터의)를 반환한다. 현재 위치 지정자를 파일 끝으로 이동 시켜 놓았기 때문에 tellg 함수는 파일의 크기(바이트 단위)로 반환한다. 그리고 문자열에 그 만큼의 크기를 할당한다.

// 그리고 그 위치를 읽는다. (파일의 크기)
int size = in.tellg();

 

이제 파일을 읽어주기 위해, 끝으로 옮겨 놓은 파일 위치 지정자를 다시 처음으로 옮겨주어야 한다. 옮기지 않을 경우 위치 지정자가 파일 끝에 있으므로 아무것도 읽지 못할 것이다.

// 위치 지정자를 다시 파일 맨 앞으로 옮긴다.
in.seekg(0, std::ios::beg);

 

마지막으로 파일 전체에 내용을 문자열에 저장하면 된다.

// 파일 전체 내용을 읽어서 문자열에 저장한다.
in.read(&s[0], size);

 

 

 

파일 전체를 한 줄씩 읽기

파일 전체를 while문을 통해 한 줄씩 읽으려면 아래의 코드를 사용하면 된다.

// getline 으로 읽어들이기
#include <fstream>
#include <iostream>
#include <string>

int main() {
	// 파일 읽기 준비
	std::ifstream in("test.txt");
	char buf[100];
	if (!in.is_open()) {
		std::cout << "파일을 찾을 수 없습니다!" << std::endl;
		return 0;
	}
	while (in) {
		in.getline(buf, 100);
		std::cout << buf << std::endl;
	}
	return 0;
}

이제 위 코드를 아래에서 자세히 이야기해보자.

 

ifstream 객체의 멤버 함수로 존재하는 getline 함수는 파일에서 개행문자(\n)이 나올 때까지 최대 지정한 크기 -1만큼 읽게 된다. 하나를 적게 읽는 이유는, buf의 맨 마지막 문자로 널 종료 문자를 넣어줘야 하기 때문이다. 따라서 아래의 경우 buf에 최대 99글자까지 입력 받는다.

in.getline(buf, 100);

 

물론 개행 문자 말고도 다른 지정한 문자가 나올 때 까지 읽는 것으로 변경할 수도 있다. 이 경우 원하는 문자를 인자로 전달해주면 해당 문자가 나올 때까지 입력 받는다. 아래의 경우 마침표(.)가 나올 때까지 buf에 최대 99글자까지 입력 받는다.

in.getline(buf, 100,'.');

 

while(in){

ifstream에는 자기 자신을 bool로 캐스팅 할 수 있는 캐스팅 연산자(operator bool())가 오버로딩 되어 있다. 따라서 위와 같이 while문 조건에 in을 전달한다면 bool로 캐스팅하는 연산자 함수가 호출된다. 이 때 in이 true이기 위해서는 다음 입력 작업이 성공적이어야만 하고 현재 스트림에 오류 플래그가 켜져 있지 않아야 한다.

하지만 getline함수는 개행 문자(혹은 지정한 문자)가 나오기 전에 지정한 버퍼의 크기가 다 차게 된다면 failbit를 키게 되므로 버퍼의 크기를 너무 작게 만든다면 정상적으로 데이터를 받을 수 없다. 따라서 getline을 사용하기 전에 이와 같은 조건을 꼭 확인해야 한다.

이와 같은 한계를 극복하기 위해서 std::string에서 getline함수를 제공하고 있다.

// std::string 에 정의된 getline 사용
#include <fstream>
#include <iostream>
#include <string>

int main() {
	// 파일 읽기 준비
	std::ifstream in("test.txt");
	if (!in.is_open()) {
		std::cout << "파일을 찾을 수 없습니다!" << std::endl;
		return 0;
	}
	std::string s;
	while (in) {
		getline(in, s);
		std::cout << s << std::endl;
	}
	return 0;
}

위 코드에서의 getline함수는 ifstream에 정의되어 있는 것이 아닌, std::string에 정의되어 있는 함수로, 첫 번째 인자로 istream객체를 받고, 두번째 인자로 입력 받은 문자열을 저장할 string 객체를 받게 된다. 굳이 버퍼의 크기를 지정하지 않아도 알아서 개행문자 혹은 파일에 끝이 나올 때 까지 입력받는 다는 점이 기존 ifstream의 getline을 활용할 때 보다 훨씬 편리하다.

 

 

 

modoocode.com/312

 

씹어먹는 C++ 강좌 - PDF 파일

 

modoocode.com

 

728x90
반응형

'Development > C & C++' 카테고리의 다른 글

[c++] std::ofstream 연산자 오버로딩  (0) 2021.01.03
[c++] 파일에 쓰기  (0) 2021.01.03
[c++] 파일 입출력  (0) 2021.01.03
[c++] 형식 플래그(format flag)와 조작자(Manipulator)  (0) 2021.01.03
[c++] cin (입력 받기)  (0) 2021.01.02
Comments