본문 바로가기

별걸다하는 IT/프로그래밍언어

[C++ 씨플플] 파일입출력 ifstream ofstream fstream 사용법. C언어와 C++ 파일입출력 차이. 파일읽고쓰는법

[C, C++ 완전정복 목차]

 

안녕하세요~~양햄찌주인장입니다.

최근에 데이터베이스 카테고리 포스팅 개수 좀 채운다고 언어관련 포스팅은 못썼었는데, 간만에 작성하는 C++ 글이네요 ㅋㅋ

 

오늘은 뭘 쓸까 고민하다가~~~

접때 C언어 파일입출력 fopen과 fclose에 대해 알아봤는데 오늘은 C++ 스타일 파일 입출력에 대해 작성해보려고 합니다. 해당 포스팅을 학습하기 전에 파일입출력에서 스트림이 무엇인지에 대한 개념은 숙지하고 계셔야 합니다.

해당 내용이 궁금하신 분은 아래 포스팅을 참고해주세요.

 

스트림(STREAM)에 대한 이해와 fopen & fclose : jhnyang.tistory.com/196

 

[C언어] 파일입출력 -스트림(STREAM)에 대한 이해, fopen, fclose

[C/ C++ 프로그래밍 기초 목차] 오랜만에 사용해보는 기본스티커 ㅎㅎㅎ 안녕하세요. 즐거운(?) 주말이예요 ㅎㅎ 오늘은 파일입출력에 관한 포스팅을 들고 왔숩니다. 오랜만에 옛날에 배운걸 더듬

jhnyang.tistory.com

C언어 파일입출력과 C++ 파일입출력 차이가 무엇일까요?

[C언어]

C언어의 경우 위 포스팅에서 보았듯이 함수를 통해 스트림을 형성하고 필요한 정보를 파일구조체에다가 받아서 포인터로  접근해 사용합니다. 그리고 해당 파일로부터 읽고 싶거나, 또는 어떤 파일에 데이터를 쓰고 싶으면 파일입출력 관련 함수를 이용해서 코드를 짜줘요. (fputs, fputc, fgets 등등)

 

[C++언어]

그런데 C++은 이런 스트림 관련 기능과 파일입출력 함수와 같은 관련 함수들을 묶어서 클래스로 제공하고 있어요.

즉 FILE 구조체를 복잡한 포인터로 사용하지 않고 정보를 객체에 저장합니다. 세부적인건 우리가 몰라도 되도록요!

또 기존 C++ 스탠다드 입출력 형식과 매우 유사하게 통일함으로써 헷갈림을 방지합니다!

 

cout << "hello"; //모니터 콘솔에 hello 출쳑!
out << "hello"; //파일스트림 out에 등록된 파일에 hello 출력!
//--> 둘다 동일하게 연산자 오버로딩을 통해 간단하게 읽고 쓰기 가능!

예를 들어, C++에서 hello를 출력하려면 cout << "hello"; 해줬었죠?

파일에다가 출력하려면 out << "hello"; 라고 써주면 됩니다. (out은 파일입출력 스트림 객체) 

C언어처럼 함수이름을 외울필요는 없죠~

 

ifstream, ofstream, fstream

암튼 파일스트림에 관한 클래스가 ifstream, ofstream, fstream입니다.

파일을 읽기만 할거면 ifstream을, 파일이 쓰기만 할거면 ofstream을, 읽고쓰는거 같이 할거면 fstream을 사용하는거.

ifstream의 i를 input의 약자, ofstream의 o를 output의 약자, fstream은 두개를 합친거라 앞에가 없는거라고 생각하면 헷갈리지 않고 기억하실 수 있어요.

앞의 out객체는 파일에 출력하는거니까 ofstream 객체가 되겠죠ㅎㅎ 

 

헤더 라이브러리

헤더는 #include <fstream> 추가해주면 됩니다.

파일 연결하기 - open 멤버함수

파일을 스트림에 연결하고 싶을 때에는 open 멤버함수를 사용합니다.

이 함수는 외부 파일과 프로그램 사이에 다리를 놓는 역할을 해요. 그리고 스트림을 진행하기 위해 필요한 정보들을 모드 스트림 객체에 저장합니다. 

ifstream fin;           //파일입력스트림 객체 fin을 선언 (file input의 약자)
fin.open("input.txt");  // fin 정보를 이용해 input.txt 파일을 연결한다.

ofstream fout;			 //파일출력스트림 객체 fout을 선언 (file output의 약자)
fout.open("output.txt"); // fout 정보를 이용해 output.txt 파일을 연결한다.

fin, fout은 제멋대로 임의로 지은 객체명입니다. 여러분이 잘 식별할 수 있는 객체명을 지어주면 돼요. 

 

ifstream fin("input.txt");

ofstream fout("output.txt");

근데 두줄에 쓰려니까 너무 귀찮죠. 해당 코드는 이처럼 한 줄로 줄여서 사용할 수 있습니다. 

파일이 없을 경우 예외처리하기 - fail 멤버함수

그런데 만약 파일을 읽어드리려고 했는데 해당 파일이 위치에 없을 수 있겠죠! 존재하지 않는 파일일수도 있고요. 그렇다고 컴파일이 에러나지는 않지만, 해당 상황을 잡아주지 않으면 처리하는 과정에서 충분히 문제가 생길 수 있어요.

#include <fstream>
#include <iostream>
using namespace std;
int main() 
{
	ifstream fin("input.txt");
	if (!fin) 
	{
		cerr << "파일을 찾을 수 없음" << endl;
		exit(100);
	}
	return 0;
}

요렇게 해주셔도 되고 아님 좀 더 보기 명료하게 클래스에 있는 함수를 사용해서 표현할 수도 있습니다.

#include <fstream>
#include <iostream>
using namespace std;
int main() 
{
	ifstream fin("input.txt");
	if (fin.fail()) 
	{
		cerr << "파일을 찾을 수 없음" << endl;
		exit(100);
	}
	return 0;
}

저는 이 방법을 좀 더 선호하는 편이예요. fail과 반대되는 멤버함수로는 is_open()이 있습니다. 해당 값이 true이면 파일이 존재한다는 뜻~!

 

파일 연결 해제하기 - close 멤버함수

파일을 열었으면 파일을 닫아줘야겠죠.

C언어에서는 fopen으로 파일을 열고, fclose로 파일을 닫아줬어요. 리소스를 낭비할 수 있기에 꼭 꼭 닫아줘야 했었죠.

그런데 C++은 OOP로 가장 큰 장점은 RAII가 지원된다는거죠. 이 말은 무슨말이냐 소멸자가 있어서 스코프가 끝나면 자동으로 자원을 해지시켜준다는 겁니다. 

그래서 위 소스코드 예시처럼 close를 작성하지 않아도 크게 문제되지는 않아요. 하지만 당연히 명료하게 작성해주는 습관을 갖는게 좋겠죠?

#include <fstream>
#include <iostream>
using namespace std;
int main() 
{
	ifstream fin("input.txt");
	if (fin.fail()) 
	{
		cerr << "파일을 찾을 수 없음" << endl;
		exit(100);
	}
	fin.close(); //!요부분~!!
	return 0;
}

 

파일에 문자열 쓰기 - put과 <<연산자

기본적인건 다 끝났습니다. 그럼 파일에다가 글 쓰는 프로그램을 작성해보도록 해요.

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
	ofstream fout("output.txt");
	fout << "hello wolrd!\n";
	fout.put('A');
	fout.put('B');
	fout.close();
	return 0;
}

쓰는건 똑같아요. cout 으로 출력해줬던 것처럼 똑같이 해주면 됩니다.

그 외 한글자씩 파일에 쓰는 멤버함수도 put도 있어요. 이 외에 write라는 멤버함수도 있는데 요 애는 일반텍스트파일이 아닌 바이너리데이터를 쓸 때 사용됩니다. 

실행해보시면 해당 소스파일이 있는 위치에 이렇게 딱 파일이 생겼습니다.

텍스트 파일을 열어보면, 우리가 짰던대로 문자열이 적혀있는 것을 확인하실 수 있어요.

 

파일로부터 문자열 읽기 - get, getline 과 >>연산자

앞에서 작성했던 output.txt 파일을 읽어볼까요?

출력했을 때랑 마찬가지로 읽는데에도 get과 >>연산자가 있고 추가적으로 라인 바이 라인 읽어주는 getline 멤버함수가 있어요. read라는 멤버함수는 마찬가지로 바이너리 데이터를 읽을 때 사용됩니다. 이번엔 먼저 get으로 읽어볼게요.

[ifstream::get]

#include <iostream>
#include <fstream>
int main()
{
	ifstream fin("output.txt");
	char c;
	while (fin.get(c))   //파일입력
		std::cout << c;  //표준입출력 출력
	fin.close();
	return 0;
}

읽는게 성공하면, 내가 체크할 수 있게 콘솔창에 출력하게끔 작성했습니다. put이 한 글자만 썼던거처럼 get은 한 글자만 읽어줍니다. 텍스트 문자열 전체를 읽기 위해 반복문을 사용했어요.

잘 읽은 것을 확인할 수 있습니다!

 

[get vs getc vs gets / put vs putc vs puts]

많은 친구들이 get이랑 getc, gets 그리고 put, putc, puts 함수를 헷갈리는데

get과 put은 요 파일입출력 클래스에 내장되어 있는 멤버함수입니다. putc와 puts는 stdio.h 라이브러리에 정의되어있는 표준입출력 C언어 함수예요.

 

[ifstream::getline]

이번엔 getline을 이용해 읽어봅시다. 

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
	ifstream fin("output.txt");
	char line[100];
	while(fin.getline(line, sizeof(line)))
		cout << line << endl;
	fin.close();
	return 0;
}

결과는 위와 동일합니다. getline은 표준입출력 istream 클래스로부터 물려받은 함순데요 

getline에 대해서는 하기 포스팅에서 자세히 다뤘던 적이 있어요. 궁금하신 분을 아래 포스팅을 참고해주세요. 

▼ C언어 문자열 인자로 받는 getline과 C++ string의 getline: jhnyang.tistory.com/107

 

C언어 istream::getline()과 C++ string의 getline()! 한 줄 읽는 함수가 두 개?

[C언어, C++언어, JAVA언어 포스팅 링크, 라이브러리 함수 모음 링크] [C/C++] 포스팅에 들어가기 전 cstring vs string.h vs string 스트링클래스 차이(C-strings vs std::string) 이 포스팅을 먼저 읽고 보길..

jhnyang.tistory.com

[ifstream::>>연산자]

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
	ifstream fin("output.txt");
	char line[100];
	while (!fin.eof())
	{
		fin >> line;
		cout << line << endl;
	}
	fin.close();
	return 0;
}

cin>> 이 그랬듯 여기서도 whitespace를 기준으로 읽씁니다. 즉 띄어쓰기나 엔터 나오기 전까지 자른다!

eof는 파일이 끝인지 아닌지 체크해주는 함수예요.

그래서 결과는 요렇게 됩니다.ㅎㅎ

 

오늘은 아주 기초적인 씨플플 파일입출력에 대해 알아봤어요~! 이정도면 기본적인 파일 읽고 쓰기는 가능하시겠쥬~?

많이들 어려워하는데 알고나면 하나도 어려운 부분이 아니라는거~~!

도움이 되셨다면 공감/광고보답/댓글 조아요 언제나 큰 힘이 됩니다 그럼 오늘도 꾸벅 담에 봐요!