KoreanFoodie's Study

C++ 기초 개념 7-2 : C++에서 파일 입출력 (istream, ofstream, stringstream) 본문

Tutorials/C++ : Beginner

C++ 기초 개념 7-2 : C++에서 파일 입출력 (istream, ofstream, stringstream)

GoldGiver 2022. 1. 10. 15:54

모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요!

fstream

파일 스트림클래스 fstream을 상속받아 istream과 ostream을 입출력 클래스로 사용하자.

std::ifstream in("test.txt");
std::string s;

if (in.is_open()) {
    in >> s;
    std::cout << "입력 받은 문자열 :: " << s << std::endl;
} else {
    std::cout << "파일을 찾을 수 없습니다!" << std::endl;
}

ifstream 인 in 으로 새로운 파일을 읽는 경우가 아니라면, ifstream에서는 자동으로 close 함수를 호출해 주기 때문에, 따로 close 함수를 호출할 필요는 없다.

 

 

파일 전체 읽기

#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;
}

 

파일 전체를 한 줄씩 읽기

  // 파일 읽기 준비
  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;
  }

위의 코드는 만약 in.getline에서 100글자가 넘는 문자가 들어와 버퍼가 찼을 경우, failbit가 켜지게 된다. 따라서 다음과 같이 수정해 보자.

 

  std::string s;
  while (in) {
    getline(in, s);
    std::cout << s << std::endl;
  }

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

while 문 조건으로 절대 in.eof( )를 사용하면 안된다(이런 코드는 99.9% 잘못된 코드). 왜냐하면 eof 함수는 파일 위치 지시자가 파일의 끝에 도달한 이후에 true를 리턴하기 때문이다. 예를 들어 파일 끝(EOF) 바로 직전까지 읽었다고 해 보자. 아직 끝까지는 읽지 않았으니 in.eof( )는 참인 상태이겠지만, 그 상태에서  in >> s 를 하게 되면 s에는 아무것도 들어가지 않게 된다.

따라서, in.eof( )는 while 문 안에서 파일 읽기가 안전하다라는 것을 보장하지 않는다. 정확한 사용법은 그냥 while(in) 처럼 스트림 객체 자체를 전달하는 것이다.

 

 

파일에 쓰기

  std::ofstream out("test.txt");

  std::string s;
  if (out.is_open()) {
    out << "파일이 없으면 생성, 있으면 덧붙여짐";
  }

output 파일 스트림을 생성할때는 여러 옵션을 줄 수 있다. (ios::app, ios::binary 등등)

 

 

std::ofstream 연산자 오버로딩 하기

이전의 연산자 오버로딩과 원리는 같다.

class Human {
  std::string name;
  int age;

 public:
  Human(const std::string& name, int age) : name(name), age(age) {}
  std::string get_info() {
    return "Name :: " + name + " / Age :: " + std::to_string(age);
  }

  friend std::ofstream& operator<<(std::ofstream& o, Human& h);
};

std::ofstream& operator<<(std::ofstream& o, Human& h) {
	o << h.get_info();
	return o;
}


int main() {

	std::ofstream out("test.txt");

	Human h("Tony", 30);
	out << h << std::endl;

	return 0;
}

 

 

문자열 스트림 (std::stringstream)

sstream에 정의된 stringstream을 이용하면, 입력받은 문자열을 마치 스트림처럼 사용할 수 있어 타입 변환이 매우 편리해진다!

#include <iostream>
#include <sstream>
#include <string>

double to_number(std::string s) {
  std::istringstream ss(s);
  double x;

  ss >> x;
  return x;
}
int main() {
  std::cout << "변환:: 1 + 2 = " << to_number("1") + to_number("2") << std::endl;

  return 0;
}

숫자를 문자로 변환한다고 하면 반대로 ss.str( )함수를 호출하면 끝이다.

 

 

Comments