Turbo-C
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
터보-C 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
Lua 게시판
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C/C++ 강좌/문서
[37] (08) Stream & File in C++ (1)
남병철.레조 [lezo] 19407 읽음    2009-06-21 12:16


[목차]

(1) Stream Class & Error
(2) File I/O (by stream)
(3) File I/O (by member function)
(4) Memory for stream object
(5) Print and etc.










(1) Stream Class & Error
    스트림은 입출력 상황의 데이터 흐름을 가리키는 일반적 이름이다.
    특히, C++의 스트림은 iostream이라고도 불리며 특정 Class의 객체로 나타낼 수 있다.

    [Stream Class의 장점]
    1. Stream Class는 오류에 잘 노출되지 않는다.
       Ex) printf()에 %f를 사용해야 할 때 %d를 사용하는경우.
    2. 삽입(<<) 및 추출(>>) 연산자와 같은 기존 연산자나 함수를 겹지정하면 자신이 만드는
       Class를 다룰 수 있다.

    [Stream을 사용하는 이유]
    문자 정보를 직접 화면에 출력하지 않는 Windows와 같은 GUI 환경에서 프로그래밍하려
    하는데 왜 C++ 스트림 입출력이 중요한지 의아할 것이다. 그 이유는, iostream은 데이터를
    파일에 써넣고 대화 상자나 다른 GUI 요소에 나중에 사용하기 위해 메모리의 데이터를
    서식 설정하는 최선의 방법이기 때문이다.



    * ios Class
    ios Class는 모든 Stream Class의 선조이며 C++ Stream을 조작하는데 필요한 대부분의
    특징을 포함한다.
    가장 중요한 세 기능은 1. 서식 설정 플래그, 2. 오류 상태 비트, 3. 파일 연산 모드


    * manipulator
    manipulator는 Stream에 직접 삽입되는 서식 설정 지시이다.
    인수를 갖지 않는 manipulator(조정자)는 iostream.h에 있으며 인수를 갖는 manipulator는
    iomanip.h에 선언되어있다.
    manipulator는 인수 있는것과 없는것이 있으며 같은 기능으로 대응되는 구성원 함수가있다.

    [무인수 ios 조정자]----------------------------------------------------------------------
    <조정자>			<목적>
    dec				10진으로 변환
    oct				8진으로 변환
    hex				16진으로 변환
    left			
    endl			새줄을 삽입하고 출력 스트림을 비운다.
    ends			널문자를 사용하여 출력 문자열을 종료시킨다.


    [유인수 ios 조정자]----------------------------------------------------------------------
    <조정자>			<인수>				<목적>
    setw( int )			필드 너비(int)			출력의 필드 너비를 설정한다.
    setfill( int )		채우기 문자(int)		출력의 채우기 문자를 설정한다.
								(기본값은 빈칸)
    setprecision( int )		정밀도(int)			정밀도(표시되는 자리수) 설정
    setiosflags( long )		서식 설정 플래그(long)		지정된 플래그를 설정
    resetiosflags( long )	서식 제거 플래그(long)		지정된 플래그를 지운다.


    [함수]
//---------------------------------------------------------------------------
// 작성일 : 2002.07.04
// 제  목 : 서식 설정 예제들
// 작성자 : 남병철
//---------------------------------------------------------------------------
#include 
#include 

 void main()
{
	cout << "abcd\n" << "ABCDEFG" << endl;	
	// 끝자리 반올림(123.457)
	cout << 123 << endl << 123.4567 << endl; 

	// 넓이 지정
	cout << setw( 6 ) << "ABCD" << setw( 10 ) << "abc\n" << endl;

	// 전체 8자리, 소수점 이하 5자리, 마지막에 남으면 반올림.
	// []1.23457  -> 전체 8자리
	//     ^^^^^  -> 소수점 이하 5자리
	//            -> 마지막 '7'은 반올림되어 만들어진 수
	cout << setw( 8 ) << setprecision( 5 ) << 1.234567 << endl;
	// 빈자리 채우기
	cout << setw( 5 ) << setfill( '0' ) << 15 << endl; 

	cout << endl;
	cout << hex << 123 << endl; // 16진수
	cout << oct << 123 << endl; // 8진수
	cout << dec << 123 << endl; // 10진수
	cout << hex << -123 << endl;
	cout << oct << -123 << endl;
	cout << dec << -123 << endl;

	int x = 90;
	cout << x << endl;
	cout << char( x ) << endl;
	char xx = 'A';
	cout << int( xx ) << endl;

	double y[] = { 12.345, 3.14, 9.8765, 3.21, 56.789 };
	

	// cout 출력 멤버 함수
	// setf() 2인수 버전
	// 첫번째(설정할 플래그)     두번째(지울 필드)
	// dec, oct, hex             basefield
	// left, right, internal     adjustfield
	// scientific, fixed         floatfield
	for( int i = 0; i < 5; i++ )
	{
		// 값얻기
		cout << cout.fill() << "   ";
		cout << cout.precision() << "   ";
		cout << cout.width() << "   ";

		// 값 세팅 및 출력
		// 1
		cout.width( 8 );
		cout.fill( '*' );
		cout.setf( ios::left, ios::adjustfield );
		cout.precision( 3 );
		cout << y[i] << endl;
		// 2
		cout.width( 8 );
		cout.unsetf( ios::left );
		cout.setf( ios::right );
		cout.fill( '_' );
		cout.precision( 4 );
		cout << y[i] << endl;
	}


	cout << endl;
	char mun = 'A';

	// put( char )
	// mun를 화면에 출력
	for( int i = 0; i < 5; i++ )
		cout.put( mun++ );
	cout.put('\n');

	struct Myt {
		char name[7];
		char juso[6];
	} A = { "NamBC", "What" };
	
	// write( char*, n )
	// char*가 가리키는 주소이후의 n바이트만 화면에 표시
	cout.write( ( char* )&A, 13 );



	// 한 문자만 입력받음
	// cin 입력 멤버 함수에 대하여
	// get( char ch ) : 1문자를 ch에 입력 받는다. 입력은 엔터로 종료한다.
	char ch;
	cout << endl << "Please type one char : ";
	cin.get( ch );
	cout << ch << endl;
	cout.flush();

	// 공란이 포함된 문자열을 입력받음
	// get( char* buf, int n ) : n-1문자를 buf에 입력 받는다.
	char buf[50];
	cout << "What is your name ? ";
	cin.get( buf, 5 );
	cout << buf;

	// 지정 문자 앞까지만 입력 받음
	// getline( char* buf, int n, '문자' ) : get 2인수와 같으나 '문자' 앞까지만 buf에 수록
	char name[10];
	cout << "Your name ? ";
	cin.getline( name, 10, '.' );
	cout << endl << "Name is " << name;

	// 무조건 특정 문자수 만큼을 입력 받음
	// read( char* buf, int n ) : n문자를 buf에 입력 받는다.
	char new_name[10];
	cout << "Name : ";
	cin.read( name, 5 );
	cout << "Name is " << name;

}
//---------------------------------------------------------------------------
========================================================================================= 조정자 그와 대응되는 구성원 함수로 내용을 풀어나가자. ㅋㅋㅋ 그냥 남겨 둬봤음.. -,- - 서식 설정 플래그 ios에 있는 enum 정의의 집합으로 입출력 서식과 연산의 여러 측면에 대한 항목을 지정하는 on/off 스위치이다. 서식 설정 플래그는 ios Class의 구성원이므로 그 앞에 ios와 스코프(::)연산자가 들어 간다. 또한 ios 구성원 함수인 setf(), unsetf()를 사용하여 설정한다. Ex) cout.setf( ios::left ); cout << "This text is left-justified"; cout.unsetf( ios::left ); ========================================================================================= * 미리 정의된 stream 객체들 istream과 ostream에서 유도된 iostream Class는 다른 Class 즉, iostream_withassign Class가 유도될 수 있는 기초 Class역할만 한다. iostream Class는 자체 함수를 갖지않는다. 그러나 iostream Class에서 유도된 _withassign들은 그 객체를 복사할 수 있도록 해 주는 겹지정 대입 연산자를 포함한다. 복사할 수 있는것은 그 객체는 물론 데이터를 가지고있는 streambuf 객체도 복사해야하는 상황에 처하며 이는 같은 데이타를 중복 생성하는 비효율을 낳으므로 좋지않다. 하지만 재지정과 같은 경우에는 필요하기도 하므로 두가지로 구별되어있다. 즉, istream, ostream, iostream은 복사생성자와 대입연산자를 private으로 만들어 복사할 수 없도록 만들어져있고 이것들로부터 유도된 _withassign Class는 복사할 수 있어야한다. [미리 정의된 스트림 객체들] 이름 클래스 용도 cin istream_withassign 키보드 입력 cout ostream_withassign 일반 화면 출력 cerr ostream_withassign 오류 출력 clog ostream_withassign 로그 출력 cout 버퍼에 들어간 후 화면출력, 재지정 가능 cerr 버퍼에 들어가지 않고 화면출력, 재지정 불가능 clog 버퍼에 들어간 후 화면출력, 재지정 불가능 * 스트림 오류 스트림 오류 상태 비트는 입력이나 출력 연산에서 발생한 오류를 보고하는 ios enum 구성원이다. ===================================================== 이름 의미 ===================================================== goodbit 오류가 없음(비트를 설정하지 않음. 값 = 0) eofbit 파일 끝에 이름 failbit 연산이 실패함(사용자 오류, 때이른 EOF) badbit 유효하지 않은 연산(관계가 없는 streambuf) hardfail 복구할 수 없는 오류 ===================================================== [ ][ ][ ][ ][ ][ ][ ][ ] ^^^^^^^^^^^^^^^^ | | | L eofbit 0x01 사용하지않음 | | L failbit 0x02 | L badbit 0x04 L hardfail 0x08 ios 함수를 사용하여 오류 비트를 읽고 설정할 수 있다. ============================================================================================= 함수 목적 ============================================================================================= int = eof(); EOF 비트가 설정되면 참을 리턴한다. int = fail(); fail, bad 또는 hard-fail 비트가 설정되면 참을 리턴한다. int = bad(); bad 또는 hard-fail 비트가 설정되면 참을 리턴한다. int = good(); 모든 것이 좋으면 참을 리턴한다. 비트는 설정하지 않는다. clear(int = 0); 인수가 없으면 모든 오류 비트를 지운다. 그렇지 않으면 clear(ios::failbit)와 같이 지정된 비트를 설정한다. ============================================================================================= * 숫자입력 키보드나 디스크에서 읽은 숫자에 적용된다. 오류 상태비트를 채크해서 입력이 숫자인지 아닌지를 구별한다. 입력한후 여분의 문자가 남게되면 입력 스트림에 남으며 이것은 다음 입력 연산에 원래의 목적이 아닌데도 전달된다. 이런 불필요한 줄을 없애려면 istream의 ignore( MAX, DELIM ) 구성원 함수를 사용한다. 이것은 지정된 구분 문자까지(DELIM) 포함하여 최대 MAX 문자를 읽어서 폐기한다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.10
// 제  목 : 숫자입력이 좋을때까지 입력
// 작성자 : 남병철
//---------------------------------------------------------------------------
#include 

void main()
{
	int I;

	// 숫자만 입력 ( 엔터만 입력하면 내려감 )
	while(1) {
		cout << "\nEnter an integer: ";
		cin >> I;
		if( cin.good() ) {
			cin.ignore( 10, '\n' );
			break;
		}

		cin.clear();
		cout << "Incorrect input";
		cin.ignore( 10, '\n' );
	}
	cout << "integer is " << I << endl;


	// 입력이 없는 입력 처리
	while( 1 ) {
		cout << "\nEnter an integer : ";
		cin.unsetf( ios::skipws ); // 공백을 무시하지 않음
		cin >> I;
		if( cin.good() ) {
			cin.ignore( 10, '\n' );
			break;
		}
		cin.clear();
		cout << "Bad";
		cin.ignore( 10, '\n' );
	}
	cout << "Good";
}
//---------------------------------------------------------------------------
* 문자열과 문자의 입력 사용자가 문자열이나 문자를 입력할 때 실수를 하기는 힘들것이다.(숫자또한 문자이므로) 그러나 디스크 파일에서 읽어오는 문자나 문자열의 경우는 EOF등의 뭔가 잘못된(?) 것이 발견될 경우 오류 검사를 해야한다. 즉, 숫자의 경우와는 달리 문자열과 문자를 다룰때는 공백을 무시하는것이 좋다. [오류가 없는 Distance] 이 프로그램은 사용자로부터 피트와 인치 단위의 Distance 값을 받아서 화면 출력한다. 사용자가 입력 오류를 범하면, 프로그램은 입력을 거부하고 사용자에게 적절한 설명과 함께 입력에 대한 프롬프트를 표시한다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.11
// 제  목 : 오류가 없는 Distance Class
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 		// strchr()
#include 		// atoi()

//---------------------------------------------------------------------------

int isint( char* );
const int IGN = 10;

//---------------------------------------------------------------------------

class English 
{
	private:
		int feet;
		float inches;

	public:
		English() { feet = 0; inches = 0.0; }
		English( int ft, float in )
		{ feet = ft; inches = in; }
		void showdist()
		{ cout << feet << "\'" << inches << '\"'; }
		void getdist();
};

//---------------------------------------------------------------------------
// 사용자로부터 길이를 입력 받음
void English::getdist()
{
	char instr[80];

	while( 1 )
	{
		cout << "\n\nEnter feet : ";
		cin.unsetf( ios::skipws );
		cin >> instr;
		if( isint( instr ) )
		{
			cin.ignore( IGN, '\n' );
			feet = atoi( instr );
			break;
		}
		cin.ignore( IGN, '\n' );
		cout << "Feet must be an integer\n";
	}

	while( 1 )
	{
		cout << "Enter inches : ";
		cin.unsetf( ios::skipws );
		cin >> inches;
		if( inches >= 12.0 || inches < 0.0 )
		{
			cout << "Inches must be between 0.0 and 11.99\n";
			cin.clear( ios::failbit );// 인위적으로 failbit를 설정
		}
		if( cin.good() )
		{
			cin.ignore( IGN, '\n' );
			break;
		}
		cin.clear();
		cin.ignore( IGN, '\n' );
		cout << "Incorrect inches input\n";
	}
}

// 문자열 char*가 int를 나타내면 참을 리턴
int isint( char* str )
{
	int slen = strlen( str );
	if( slen == 0 || slen > 5 )
		return 0;
	for( int j = 0; j < slen; j++ )
		if( ( str[j] < '0' || str[j] > '9' ) && str[j] != '-' )
			return 0;

	long n = atol( str );
	if( n < -32768L || n > 32767L ) // 정수의 범위 지정
		return 0;
	return 1;
}

//---------------------------------------------------------------------------

void main( void )
{
	English d;
	char ans;
	do
	{
		// 사용자로부터 값을 입력 받음
		d.getdist();
		cout << "\nDistance = ";
		// 입력 값을 화면 출력
		d.showdist();
		cout << "\nDo another (y/n)? ";
		cin >> ans;
		// \n을 포함하여 IGN만큼 삭제
		cin.ignore( IGN, '\n' );
	} while( ans != 'n' );
}

//---------------------------------------------------------------------------
(2) File I/O (by stream) * 서식화 파일 입출력 ofstream outfile("fdata.txt"); 이 초기화는 파일에 이용할 변수 자원을 따로 설정해 두고 디스크에서 그 이름의 파일을 사용 하거나 연다. 파일이 없으면 만든다. 파일이 있으면 길이에 맞게 잘라 이전 데이타를 새 데이타로 대체한다. 프로그램이 종료하면 outfile 객체는 범위를 벗어나고, 파괴자가 호출되어 파일을 닫으므로 몇시적으로 닫을 필요 없다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.12
// 제  목 : ofstream으로 데이타 쓰기
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

void main()
{
	// 데이타 쓰기
	char ch = 'x';
	int j = 77;
	double d = 6.02;
	char str1[] = "Kafka";
	char str2[] = "Proust";

	ofstream outfile( "fdata.txt" );

	outfile << ch
			<< j
			<< ' '
			<< d
			<< str1
			<< ' '
			<< str2;
}

//---------------------------------------------------------------------------
위에서 서식설정한 순서에 맞게 데이타를 읽어보자. 제대로 서식설정 했다면 그것을 추출하고 적절한 변수에 저장해서 화면 출력하는데 문제가 없을 것이다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.12
// 제  목 : ifstream으로 데이타 읽기
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

const int MAX = 80;

//---------------------------------------------------------------------------

void main()
{
	// 데이타 읽기
	char ch;
	int j;
	double d;
	char str1[MAX];
	char str2[MAX];

	ifstream infile( "fdata.txt" );

	infile >> ch >> j >> d >> str1 >> str2;

	cout << ch << endl
		 << j << endl
		 << d << endl
		 << str1 << endl
		 << str2 << endl;
}

//---------------------------------------------------------------------------
* 공백 포함 문자열 공백이 있는 문자열을 읽을때는 각 문자열 뒤에 특정 구분 문자를 넣고, 추출 연산자가 아니라 getline() 함수를 사용하여 데이타를 읽는다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.12
// 제  목 : ofstream으로 데이타 쓰기 (getline()용)
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

void main()
{
	ofstream outfile( "TEST.TXT" );

	outfile << "I fear thee, ancient Mariner!\n";
	outfile << "I fear thy skinny hand\n";
	outfile << "And thou art long, and lank, and brown,\n";
	outfile << "As is the ribbed sea sand.\n";
}

//---------------------------------------------------------------------------
위에서 만든 파일의 문자열을 미리 알 수 없으므로 EOF를 발견할 때까지 한번에 한 문자열씩 읽는다. 그러나 임의의 문자 정보 파일을 읽을 때 이 프로그램을 사용하면 안 된다. 모든 문자열이 '\n'으로 끝날것을 요구하며 그렇지 않은 파일을 발견하면 프로그램이 정지할 수도 있다. [파일 끝 탐지] while( !infile.eof() ) // eof를 발견할 때까지 --> eofbin의 명시적 검사만으로는 가끔 발생하는 failbit, badbit등의 오류를 무시한다. while( infile.good() ) // 오류가 발견될 때까지 --> 더 간단하게 한다면... while( infile ) // 오류가 발견될 때까지 --> infile같은 스트림 객체들은 EOF를 포함해 오류 조건들을 채크할 수 있다. 오류 조건이 참(오류이면)이면 0값을 리턴하며 모든것이 잘되면 객체는 0이 아닌 값을 리턴한다. 이 리턴값은 사실 포인터이지만 0 또는 0이 아닌 값을 테스트하는데 포인터라는 사실자체는 그다지 중요한 의미를 가지지 않는다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.12
// 제  목 : ifstream으로 데이타 읽기 (getline()용)
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

const int MAX = 80;

//---------------------------------------------------------------------------

void main()
{
	char buffer[MAX];
	ifstream infile( "TEST.TXT" );
	while( !infile.eof() )
	{
		infile.getline( buffer, MAX );
		cout << buffer << endl;
	}
}

//---------------------------------------------------------------------------
* 문자 입출력 put(), get()을 이용하여 한번에 한 문자씩 입출력한다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.21
// 제  목 : put을 이용한 문자 파일 출력
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include 		// strlen()

//---------------------------------------------------------------------------

void main()
{
	char str[] = "Time is a great teacher, but unfortunately "
				"it kills all its pupils.  Berlioz";

	ofstream outfile( "TEST.TXT" );
	for( int j = 0; j < strlen( str ); j++ )
		outfile.put( str[j] );
}

//---------------------------------------------------------------------------
문자 출력방법에는 한 문자씩 읽어서 출력하는것이 있고 streambuf 객체에 직접접근하여 읽는 방법이 있다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.21
// 제  목 : 문자를 이용한 파일 입력
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

void main()
{
	char ch;
	ifstream infile1( "TEST.TXT" );
	ifstream infile2( "TEST.TXT" );
	// get() 함수를 사용해 EOF를 발견할 때까지 읽기를 계속
	while( infile1 )
	{
		infile1.get(ch);
		cout << ch;
	}

	// streambuf에 직접 접근하여 읽기
	cout << endl << infile2.rdbuf();
}

//---------------------------------------------------------------------------
* 2진 입출력 read(), write() 함수는 데이타의 서식은 상관하지 않고 바이트로 꽉 찬 버퍼를 디스크 파일에 전송한다. 즉, 입력되는 데이타 버퍼의 시작 포인터 타입은 바이트 단위인 char*로 캐스팅하고 데이타의 길이는 입력 데이타 타입크기*데이타 개수가 될것이다.
//---------------------------------------------------------------------------
// 작성일 : 2002.07.21
// 제  목 : Binary 파일 입출력
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

const int MAX = 100;
int buff[MAX];

//---------------------------------------------------------------------------

void main()
{
	int j;
	for( j = 0; j < MAX; j++ )
		buff[j] = j;

	ofstream os( "edata.dat", ios::binary );

	// 버퍼 포인터는 char*로 캐스팅 및 길이는 데이타 타입 크기의 개수로 지정
	os.write( (char*)buff, MAX * sizeof( int ) );
	// 명시적으로 파일 닫기
	os.close();

	for( j = 0; j < MAX; j++ )
		buff[j] = 0;

	ifstream is( "edata.dat", ios::binary );

	is.read( (char*)buff, MAX * sizeof( int ) );

	for( j = 0; j < MAX; j++ )
		if( buff[j] != j )
		{ cerr << "\nData is incorrect"; return; }

	cout << "\nData is correct";
}

//---------------------------------------------------------------------------
* 객체 입출력(Binary)
//---------------------------------------------------------------------------
// 작성일 : 2002.07.23
// 제  목 : 디스크에 객체 써넣기
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

class person
{
	protected:
		char name[40];
		int age;

	public:
		void getData( void ) {
			cout << "Enter name : "; cin >> name;
			cout << "Enter age : "; cin >> age;
		}
};

//---------------------------------------------------------------------------

void main()
{
	person pers;
	pers.getData();

	ofstream outfile( "PERSON.DAT", ios::binary );
	outfile.write( ( char* )&pers, sizeof( pers ) );
}

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 작성일 : 2002.07.23
// 제  목 : 디스크에서 객체 읽기
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

class person
{
	protected:
		char name[40];
		int age;

	public:
		void showData( void ) {
			cout << "\n   Name : " << name;
			cout << "\n   Age : " << age;
		}
};

//---------------------------------------------------------------------------

void main()
{
	person pers;
	ifstream infile( "PERSON.DAT", ios::binary );
	infile.read( ( char* )&pers, sizeof( pers ) );
	pers.showData();
}

//---------------------------------------------------------------------------
* 호환되는 데이터 구조체 가상함수를 사용하지 않는 단순한 클래스에서 구성원 함수는 객체의 데이타와 함께 기록되지 않는다. 즉, 데이타는 같은 형식(순서까지)을 가져야 하지만 객체를 읽고 쓰는데 구성원 함수는 아무런 영향을 주지 않는다. 특히, 상속받은 Class의 객체를 파일에 읽고 쓸 경우는 더욱 주의를 요한다. 가상함수를 사용하는 유도 Class의 객체는 vptr(Virtual Pointer)를 포함한다. 이 포인터는 Class에 사용된 가상 함수표의 주소를 보관하며 객체를 디스크에 써넣으면, 이 수가 객체의 다른 데이타와 함께 기록된다. 그러므로 객체를 읽는 Class는 객체를 쓰는 Class와 동일해야 한다. * fstream 클래스 파일 입출력을 하려면 iostream으로부터 유도된 fstream Class의 객체가 필요하다. open() ===================================================== 모드비트 결과 ===================================================== in 읽기 위해 연다(ifstream의 기본값) out 쓰기 위해 연다(ofstream의 기본값) ate 파일 끝에서 읽기나 쓰기를 시작 app 파일 끝에서 쓰기를 시작 trunc 파일이 존재하면 길이 0으로 절단 nocreate 파일이 아직 존재하지 않으면 열 때 오류 발생 noreplace 파일이 이미 존재하면, ate나 app가 설정된 경우를 제외하고는 출력을 위해 열 때 오류 발생 binary 파일을 2진(문자열이 아님) 모드로 연다. =====================================================
//---------------------------------------------------------------------------
// 작성일 : 2002.07.23
// 제  목 : 여러 객체를 이용한 입출력
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

class person
{
	protected:
		char name[40];
		int age;

	public:
		// 사람 데이타 받음
		void getData( void ) {
			cout << "\n   Enter name : "; cin >> name;
			cout << "   Enter age : "; cin >> age;
		}

		// 사람 데이타 화면 출력
		void showData( void ) {
			cout << "\n   Name : " << name;
			cout << "\n   Age : " << age;
		}
};

//---------------------------------------------------------------------------

void main()
{
	char ch;
	person pers;
	fstream file;

	// 추가하기 위해 연다.(파일 끝에 추가하면서 한번 열어서 2진모드로 읽고 쓰기를 함)
	file.open( "PERSON.DAT", ios::app | ios::out | ios::in | ios::binary );

	do
	{
		cout << "\nEnter person's data : ";
		pers.getData();

		file.write( ( char* )&pers, sizeof( pers ) );
		cout << "Enter another person (y/n)? ";
		cin >> ch;
	}
	while( ch == 'y' );

	// 파일의 시작위치로 초기화
	file.seekg( 0 );

	// 첫번째 사람을 읽음
	file.read( ( char* )&pers, sizeof( pers ) );
	while( !file.eof() )
	{
		cout << "\nPerson : ";
		pers.showData();
		file.read( ( char* )&pers, sizeof( pers ) );
	}
}

//---------------------------------------------------------------------------
* 파일 오류와 파일 포인터 - 오류에 반응하기
//---------------------------------------------------------------------------
// 작성일 : 2002.07.23
// 제  목 : 오류에 반응하기
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 
#include  // exit()

//---------------------------------------------------------------------------

const int MAX = 1000;
int buff[MAX];

//---------------------------------------------------------------------------

void main()
{
	int j;
	for( j = 0; j < MAX; j++ )
		buff[j] = j;

	// 파일 출력 스트림을 만든다.
	ofstream os;

	os.open( "a:edata.dat", ios::trunc | ios::binary );
	if( !os )
	{ cerr << "\nCould not open output file"; exit(1); }
	
	cout << "\nWriting...";
	os.write( ( char* )buff, MAX * sizeof( int ) );
	if( !os )
	{ cerr << "\nCould not write to file"; exit(1); }
	os.close();

	// 버퍼 지움
	for( j = 0; j < MAX; j++ )
		buff[j] = 0;

	// 입력 스트림을 만든다.
	ifstream is;

	is.open( "a:edata.dat", ios::binary );
	if( !is )
	{ cerr << "\nCould not open input file"; exit(1); }

	cout << "\nReading...";
	is.read( ( char* )buff, MAX * sizeof( int ) );
	if( !is )
	{ cerr << "\nCould not read from file"; exit(1); }

	for( j = 0; j < MAX; j++ )
		if( buff[j] != j )
		{ cerr << "\nData is incorrect"; exit(1); }
	cout << "\nData is correct";
}

//---------------------------------------------------------------------------
- 오류 분석하기
//---------------------------------------------------------------------------
// 작성일 : 2002.07.23
// 제  목 : 오류 분석하기
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

void main()
{
	ifstream file;

	file.open( "GROUP.DAT", ios::nocreate );

	if( !file )
		cout << "\nCan't open GROUP.DAT";
	else
		cout << "\nFile opened successfully";

	cout << "\nfile = " << file;
	cout << "\nError state = " << file.rdstate();
	cout << "\ngood() = " << file.good();
	cout << "\neof() = " << file.eof();
	cout << "\nfail() = " << file.fail();
	cout << "\nbad() = " << file.bad();
	file.close();
}

//---------------------------------------------------------------------------
- 파일 포인터 위치 지정하기 seekg()에서 2인수 사용시 두번째 파일 포인터 시작 위치를 지정하는데 ios::beg --> 시작 위치에서 첫번째 인수 만큼 이동 ios::cur --> 시작 위치에서 첫번째 인수 만큼 이동 ios::end --> 끝 위치에서 첫번째 인수 만큼 이동
//---------------------------------------------------------------------------
// 작성일 : 2002.07.23
// 제  목 : 위치 지정하기
// 작성자 : 남병철
//---------------------------------------------------------------------------

#include 

//---------------------------------------------------------------------------

class person
{
	protected:
		char name[40];
		int age;
	public:
		void showData( void )
		{
			cout << "\n   Name : " << name;
			cout << "\n   Age : " << age;
		}
};

//---------------------------------------------------------------------------

void main()
{
	person pers;
	ifstream infile;
	infile.open( "PERSON.DAT", ios::binary );

	infile.seekg( 0, ios::end );
	int endposition = infile.tellg();
	int n = endposition / sizeof( person );
	cout << "\nThere are " << n << " persons in file";

	cout << "\nEnter person number : ";
	cin >> n;
	int position = ( n - 1 ) * sizeof( person );
	infile.seekg( position );

	infile.read( ( char* )&pers, sizeof( pers ) );
	pers.showData();
}

//---------------------------------------------------------------------------

+ -

관련 글 리스트
37 (08) Stream & File in C++ (1) 남병철.레조 19407 2009/06/21
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.