12 장파일입출력 파일입출력의기초파일열기, 사용하기, 닫기파일입출력모드문자단위파일입출력텍스트파일과이진파일 read, write 함수에의한이진파일입출력임의접근입출력스트림상태입출력연산자오버로딩과파일입출력 C++ 프로그래밍입문
1. 파일입출력의기초 파일입출력방법 표준입출력객체인 cin, cout에해당하는파일입출력스트림객체만만들수있다면기본적인사용방법은표준입출력과동일파일입출력스트림객체의생성 <fstream> 헤더파일필요 입력객체 : ifstream fin( in.dat ); 출력객체 : ofstream fout( out.dat ); 입출력객체 : fstream fio( data.dat ); 12 장파일입출력 1
2. 파일열기, 사용하기, 닫기 파일출력과정 1. 출력스트림을위한 ofstream 객체생성 ofstream fout; 2. 생성된 ofstream 객체와데이터를출력할파일연결 fout.open( out.dat ); ü void open(const char *fname, int nmode); ü fout.open("c:\data\out.dat", ios_base::out ios_base::trunc); nmode에대해서는다음절에서설명 또는 1, 2를동시에수행 : ofstream fout( out.dat ); 3. 표준출력객체 (cout) 와동일한방법으로사용 fout << test << endl; 4. 파일연결해제 fout.close(); ü fout 객체자체가소멸되는것은아님 à fout.open() 을통해또다른파일연결가능 12 장파일입출력 2
2. 파일열기, 사용하기, 닫기 출력예 : 1 부터 20 까지의정수중 3 의배수를 out.txt 로출력 #include <iostream> #include <fstream> using namespace std; int main(void) { ofstream fout("out.txt"); // 출력스트림생성및파일열기 if (!fout) { // 에러처리 cout << " 파일열기에러 " << endl; return 1; for (int i = 1; i <= 20; i++) { if (i % 3 == 0) fout << i << " "; 파일열기도중에러발생 à failbit 이 1 로변경됨 (11.9 절 ) ofstream 클래스는! 연산자오버로딩을통해 fail 인경우 true 를반환 // 표준출력과동일하게사용 fout.close(); return 0; if (fout == NULL) { 와같이사용가능 fout 은변환함수 (15.2 절 ) 를통해 fail 인경우 NULL 로변환될수있음 12 장파일입출력 3
2. 파일열기, 사용하기, 닫기 입력예 : 파일끝 (EOF) 을만날때까지값을읽어합계를출력 int main(void) { int Num; int Sum = 0; ifstream fin("out.txt"); // 입력스트림생성및파일열기 if (fin == NULL) { cout << " 파일열기에러 " << endl; return 1; fin >> Num; cin 의사용방법과동일 while (!fin.eof()) { Sum += Num; fin >> Num; cout << " 합계 : " << Sum << endl; fin.close(); return 0; 12 장파일입출력 4
3. 파일입출력모드 void open(const char *fname, int nmode); 파일입출력모드 파일열기모드 : 읽기, 쓰기등 접근모드 : 텍스트모드, 이진모드 상수 ios_base::in ios_base::out ios_base::ate ios_base::app ios_base::trunc ios_base::binary 입력을위한파일열기 출력을위한파일열기 파일입출력관련클래스들의디폴트입출력모드 클래스 ifstream ofstream 12장파일입출력 fstream ios_base::in ios_base::out 5 의미 파일을열때파일의끝위치를찾아끝위치로이동파일의입출력은파일의모든위치에서가능 파일에대한출력은파일의끝에추가파일의출력은파일의마지막위치에만가능하지만입력은모든위치에서가능 동일한이름의파일이존재하면파일의모든내용을삭제 이진형식으로파일열기 디폴트파일열기모드 ios_base::in ios_base::out ios_base::trunc
3. 파일입출력모드 C 와 C++ 의 파일입출력모드비교 out 만설정하면자동으로 trunc 처리가됨 텍스트모드와 이진모드의차이 줄바꿈문자의변환 캐리지리턴 (\n) 라인피드 (\r) C++ 모드 C 모드 binary in out trunc app w a w r r+ w+ wb ab wb rb r+b w+b 텍스트모드의변환 12 장파일입출력 6
3. 파일입출력모드 예 : 텍스트모드와이진모드의차이 int main(void) { ofstream fout("out3.txt", ios_base::out ios_base::trunc ios_base::binary); fout << 'a' << endl << 'b' << endl << 'c' << endl; fout.close(); return 0; 텍스트모드 ios_base::binary 를삭제한경우 이진모드 ios_base::binary 를추가한경우 일반적인데이터처리방법 - 텍스트모드로저장 à 텍스트모드로읽기 - 이진모드로저장 à 이진모드로읽기 12 장파일입출력 7
4. 문자단위파일입출력 문자단위입출력함수들 기본적인사용방법은 11.7 절, 11.8 절과동일 멤버함수 int get(void); istream &get(char &) ostream &put(char) istream &get(char *, int, char = \n ) istream &getline(char *, int, char = \n ); 문자 1 개입력 설명 문자 1 개입력, 연속호출가능 문자 1 개입력, 연속호출가능 지정한개수또는줄단위문자열입력, \n 제거하지않음 지정한개수또는줄단위문자열입력, \n 제거 기타문자입력관련멤버함수 int peek(void); // 단지다음문자가무엇인지읽어옴 ( 제거 X) istream &putback(char c); // 마지막입력문자 (c) 를되돌림 12 장파일입출력 8
4. 문자단위파일입출력 예 : get, put 함수를이용한파일복사 int main(void) { ifstream fin("in4.txt"); ofstream fout("out4.txt"); if (!fin!fout) { cout << " 파일열기에러 " << endl; return 1; char ch = fin.get(); while (!fin.eof()) { fout.put(ch); fin.get(ch); // 문자하나입력 // 문자하나출력 fin.close(); fout.close(); return 0; 12 장파일입출력 9
5. 텍스트파일과이진파일 일상적인컴퓨터사용에서의텍스트파일과이진파일 텍스트파일 : 메모장에서작성한파일 이진파일 : MS 워드파일, 아래아한글파일등프로그래밍관점에서의텍스트파일과이진파일 텍스트파일 : 데이터저장시모든데이터를문자로변환하여저장하는것 예 : int a = 15; à 1 과 5 라는문자로저장 à 2바이트 이진파일 : 데이터저장시메모리의형태그대로저장하는것 예 : int a = 15; à 메모리형태그대로저장 à 4바이트 다음파일은텍스트파일인가이진파일인가? 이파일을만든프로그래머만이대답가능 텍스트파일 : A, A, A, A 4개의문자출력 이진파일 : int a = 1094795585; 를 4바이트형태그대로출력 ü 0X41414141 à AAAA 로출력됨 12 장파일입출력 10
5. 텍스트파일과이진파일 텍스트파일과이진파일을만드는방법 파일스트림클래스의멤버함수에따라달라짐 텍스트파일로저장 : << 연산자 텍스트파일로부터입력 : >> 연산자 이진파일로저장 : write 이진파일로부터입력 : read 주의사항 파일열기모드 ( 텍스트모드, 이진모드 ) 와텍스트파일및이진파일은원칙적으로무관함 그러나, 일반적으로텍스트파일은텍스트모드로열고, 이진파일은이진모드로열어작업진행 12 장파일입출력 11
6. read, write 함수에의한이진파일입출력 read, write 함수프로토타입 istream &read(unsigned char *buffer, int size); ostream &write(const unsigned char *buffer, int size); buffer : 출력또는입력데이터를저장할변수의주소 size : 데이터의크기 ( 바이트단위 ) int main(void) { ofstream fout("ex5.dat", ios_base::out ios_base::binary); // 출력스트림 double nums[4] = { 1.1, 2.2, 3.3, 4.4 ; fout.write((char *) nums, sizeof(nums)); // double(8)*4개 =32바이트출력 fout.close(); ifstream fin("ex5.dat", ios_base::in ios_base::binary); fin.read((char *) nums, sizeof(nums)); for (int i = 0; i < 4; i++) cout << nums[i] << '\t'; cout << endl; cout << " 총바이트수 : " << fin.gcount() << endl; return 0; 12 장파일입출력 12
6. read, write 함수에의한이진파일입출력 구조체변수의이진파일입출력예 struct Point { int x, y; ; int main(void) { Point Po; ofstream fout("ex6.dat",ios_base::out ios_base::app ios_base::binary); cout << " 좌표 x, y 입력 : "; cin >> Po.x >> Po.y; while (Po.x!= 0 && Po.y!= 0) { fout.write((char *) &Po, sizeof(point)); cout << " 좌표 x, y 입력 : "; cin >> Po.x >> Po.y; // Point 크기 (8) 만큼출력 fout.close(); 12 장파일입출력 13
6. read, write 함수에의한이진파일입출력 구조체변수의이진파일입출력예 ( 계속 ) cout << "<< 저장된 Point 데이터 >>" << endl; ifstream fin("ex6.dat", ios_base::in ios_base::binary); while (fin.read((char *) &Po, sizeof(point))) { cout << "(" << Po.x << ", " << Po.y << ")" << endl; fin.close(); return 0; 12 장파일입출력 14
7. 임의접근 스트림포인터 입력포인터 (get pointer) : 다음입력이수행되는위치를가리킴 출력포인터 (put pointer) : 다음출력이수행될위치를가리킴 입력과출력이진행되면자동으로입출력된바이트수만큼다음위치로이동함입력포인터와출력포인터를임의의위치로이동하는방법 seekg, seekp 함수사용 istream &seekg(streampos pos); ostream &seekp(streampos pos); istream &seekg(streamoff off, ios_base::seek_dir dir); ostream &seekp(streamoff off, ios_base::seek_dir dir); streampos, streamoff 는 long 타입과동일 값 ios_base::beg ios_base::cur 의미 파일의처음위치를기준으로새로운위치로이동 파일의현재위치를기준으로새로운위치로이동 ios_base::end 파일의마지막위치를기준으로새로운위치로이동 12장파일입출력 15
7. 임의접근 입력포인터와출력포인터의현재위치를확인하는방법 streampos tellg(); streampos tellp(); seekg와 tellg 함수의적용예 임의접근은이진파일에보다적합함 int 값들이저장되어있는경우 50 번째 int 값으로이동 fin.seekg((50-1) * 4); // 이진파일인경우가능 12 장파일입출력 16
7. 임의접근 예 : (1, 1) 의좌표를 5 개저장한후세번째좌표를 (2, 2) 로변경 struct Point { int x, y; ; int main(void) { Point Po = { 1, 1 ; fstream fio("ex7.dat", ios_base::in ios_base::out ios_base::trunc ios_base::binary); for (int i = 0; i < 5; i++) fio.write((char *) &Po, sizeof(point)); fio.seekp(2 * sizeof(point), ios_base::beg); Po.x = 2; Po.y = 2; fio.write((char *) &Po, sizeof(point)); // 출력포인터를 3 번째원소로 fio.seekg(0, ios_base::beg); // 입력포인터를첫번째원소로이동 while (fio.read((char *) &Po, sizeof(point))) { cout << "(" << Po.x << ", " << Po.y << ")" << endl; fio.close(); return 0; 12 장파일입출력 17
8. 입출력스트림상태 파일입출력스트림상태 표준입출력스트림상태의처리방법과동일 : 11.9 절 int main(void) { int a; ifstream fin("ex8.dat"); fin >> a; if (fin.fail()) cout << "fail" << endl; else cout << "not fail" << endl; 의도하는타입의데이터를읽지못하는경우 à fail fin.clear(); if (fin.fail()) cout << "fail" << endl; else cout << "not fail" << endl; fin.close(); return 0; 12 장파일입출력 18
9. 입출력연산자오버로딩과파일입출력 CPoint 클래스에대한입출력연산자오버로딩 : 7.9 절 CPoint Po; cin >> Po; cout << Po; 다음과같은방식의파일입출력을원한다면? fin >> Po; fout << Po; 원리 별도로해야할작업은없음 à istream, ostream 클래스에대한입출력연산자오버로딩만으로충분 ostream &operator<<(ostream &os, CPoint &Po) { os << "(" << Po.x << ", " << Po.y << ")" << endl; return os; ostream 클래스는 ofstream 클래스의 base 클래스이므로 fout << Po; 에서 fout 객체를받을수있음. 결국 ofstream 객체인 fout 으로출력됨. 12 장파일입출력 19
9. 입출력연산자오버로딩과파일입출력 CPoint 클래스에대한입출력연산자오버로딩예 class CPoint { private : int x, y; public : CPoint(int a = 0, int b = 0) : x(a), y(b) { friend istream &operator>>(istream &is, CPoint &Po); friend ostream &operator<<(ostream &os, CPoint &Po); ; istream &operator>>(istream &is, CPoint &Po) { is >> Po.x >> Po.y; return is; // >> 연산자오버로딩 ostream &operator<<(ostream &os, CPoint &Po) { os << Po.x << " " << Po.y << endl; return os; // << 연산자오버로딩 12 장파일입출력 20
9. 입출력연산자오버로딩과파일입출력 CPoint 클래스에대한입출력연산자오버로딩예 ( 계속 ) int main(void) { int i; CPoint Po[5]; for (i = 0; i < 5; i++) { cout << " 좌표 (x, y) 입력 : "; cin >> Po[i]; ofstream fout("ex9.dat"); for (i = 0; i < 5; i++) fout << Po[i]; fout.close(); // << : ofstream 객체에도적용가능 ifstream fin("ex9.dat"); CPoint Temp; for (i = 0; i < 5; i++) { fin >> Temp; cout << Temp;; fin.close(); return 0; 12 장파일입출력 21