컴공생의 다이어리
[c++] 파일 전체 읽기 본문
파일 전체를 한 번에 읽기
파일 전체를 한 번에 읽으려면 아래와 같은 코드를 사용하면 된다.
#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을 활용할 때 보다 훨씬 편리하다.
'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 |