본문 바로가기

고급C,C++

C++ 입력, 출력, 파일

cin.get();
cin.get();
return 0;

17장 입력, 출력, 파일

int eggs = 12;
char * amount = "dozen";
cout << &eggs; // eggs 변수의 주소를 출력
cout << amount; // 문자열 "dozen"을 출력 한다.
cout << (void *) amount; //amount 변수의 주소를 출력한다.



cout.put("W');

cout.write("string",strlen("string"));

flush(cout);
cout<<flush;

hex(cout);
cout<<hex;

oct(cout);
cout<<oct;

dec(cout);
cout<<dec;

cout.width(5);

cout.fill('*');

cout.presision(2);
부동 소수점수의 출력 정밀도 설정 : 부동 소스점수의 정밀도는 출력 모드에 따라 그 의미가 달라진다. 디폴트 모드에서는 출력되는 총 자릿수를 의미한다. 고정 소수점 표기 모드와 지수 표기 모드에서 정밀도는 소수점 아래 자릿수를 의미한다.



출력 형식 지정 상수들
ios_base::boolalpha - bool 값을 true와 false로 입력하고 출력한다.
ios_base::showbase - 출력에 진법 표시 접두어(0,0x)를 사용한다.
ios_base::showpoint - 뒤에 붙는 소수점을 표시한다. 
ios_base::uppercase - 16진 출력, E 표기에 대문자를 사용한다.
ios_base::showpos - 양수 앞에 + 부호를 사용한다.



#include <iostream>
int main(void)
{
using std::cout;
using std::endl;
using std::ios_base;

int temperature = 63;
cout<<"오늘의 수온: ";
cout.setf(ios_base::showpos); //플러스 부호 사용
cout<<temperature<<endl;

cout<<"프로그래머들에게 그 값은"<<endl;
cout<<std::hex<<temperature<<endl;
cout.setf(ios_base::uppercase); //16진 출력에 대문자 사용
cout.setf(ios_base::showbase); // 16진 출력에 0X사용
cout<<"또는"<<endl;
cout<<temperature<<endl;
cout<<true<<"!의 값은";
cout.setf(ios_base::boolalpha);
cout<<true<<"이다."<<endl;

return 0;
}


setf(long, long)을 위한 전달인자들
제2 전달인자                 제1 전달인자                           의미
ios_base::basefield      ios_base::dec                  10진법 사용
                                 ios_base::oct                    8진법 사용
                                 ios_base::hex                   16진법 사용
ios_base::floatfield       ios_base::fixed                고정 소수점 표기 사용
                                 ios_base::scientific           과학적 E 표기 사용
ios_base::adjustfield    ios_base::left                    왼쪽 정렬 사용
                                 ios_base::right                  오른쪽 정렬 사용
                                 ios_base::internal             부호 또는 진법 접두어 왼쪽 정렬 값 오른쪽 정렬



ex) ios_base::fmtflags old = cout.setf(ios_base::left,ios_base::adjustfield);
     cout.setf(old, ios_base::adjustfield);



int main(void)
{
using namespace std;
//왼쪽 정렬 사용, 플러스 부호를 출력한다.
//정밀도 3, 뒤에 붙는 0들을 출력한다.
cout.setf(ios_base::left, ios_base::adjustmentfield);
cout.setf(ios_base::showpos);
cout.setf(ios_base::showpoint);
cout.precision(3);

//과학적 E 표기 사용, 이전의 출력 형식 설정을 저장한다.
ios_base::fmtflags old = cout.setf(ios_base::scientific, ios_base::floatfield);
cout<<"왼쪽정렬:"<<endl;
long n;
for(n = 1; n <= 41; n += 10)
{
cout.width(4);
cout<<n<<"|";
cout.width(12);
cout<<sqrt(double(n))<<"|"<<endl;
}

// 내부(internal) 정렬로 변경한다.
cout.setf(ios_base::internal, ios_base::adjustfield);
//디폴트 부동 소수점 표기를 복원한다
cout.setf(old,ios_base::floatfield);

cout<<"내부(internal) 정렬:"<<endl;
for ( n = 1 ; n <= 41; n += 10)
{
cout.width(4);
cout<<n<<"|";
cout.witdh(12);
cout<<sqrt(double(n))<<"|"<<endl;
}

//오른쪽 정렬 사용, 고정 소수점 표기로 출력한다.
cout.setf(ios_base::right, ios_base::adjustfield);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout<<"오른쪽 정렬:"<<endl;
for(n = 1; n <= 41; n+=10)
{
cout.witdh(4);
cout<<n<<"|";
cout.width(4);
cout<<n<<"|";
cout.width(12);
cout<<sqrt(double(n))<<"|"<<endl;
}

return 0;
}




표준 조정자들
 조정자  호출
 boolalpha  setf(ios_base::boolalpha)
 noboolalpha unsetf(ios_base::boolalpha)
 showbase  setf(ios_base::showbase)
 noshowbase  unsetf(ios_base::showbase)
 showpoint  setf(ios_base::showbase)
 noshowpoint  unsetf(ios_base::showbase)
 showpos  setf(ios_base::showpos)
 unshowpos  unsetf(ios_base::showpos)
 uppercase  setf(ios_base::uppercase)
 nouppercase  unsetf(ios_base::uppercase)
 internal  setf(ios_base::internal, ios_base::adjustfield)
 left  setf(ios_base::left,ios_base::adjustfield)
 right  setf(ios_base::right,ios_base::adjustfield)
 dec  setf(ios_base::dec, ios_base::basefield)
 hex  setf(ios_base::hex, ios_base::basefield)
 oct  setf(ios_base::oct, ios_base::basefield)
 fixed  setf(ios_base::fixed, ios_base::floatfield)
scientific  setf(ios_base::scientific, ios_base::floatfield)


 iomanip 헤더파일
setprecision(), setfill(), setw() 함수 
#include <iostream>
#include <iomanip>
#include <cmath>

int main(void)
{
using namespace std;
//새로운 표준 조정자를 사용한다.
cout<<showpoint<<fixed<<right;

//iomanip 조정자들을 사용한다.

cout<<setw(6)<<"N"<<setw(14)<<"제곱근"<<setw(15)<<"네제곱근"<<endl;

double root;

for(int n = 10; n<=100; n+=10)
{
root = sqrt(double(n));
cout<<setw(6)<<setfill('.')<<n<<setfill(' ')
<<setw(12)<<setprecision(3)<<root
<<setw(14)<<setprecision(4)<<sqrt(root)
<<endl;
}

cin.get();
return 0;
}


cin>>hex;
cin>>oct;
cin>>dec;





check_it.cpp
#include <iostream>

int main()
{

using namespace std;
cout<<"수를 입력하세요"<<endl;

int sum = 0;
int input;
while(cin>>input)
{
sum+=input;
}
cout<<"마지막으로 입력한 값 = "<<input<<endl;
cout<<"합계 = "<<sum<<endl;

cin.get();

return 0;
}


스트림 상태
 멤버  설명
 eofbit  파일 끝에 도달하면 1로 설정된다.
 badbit  스트림이 손상되면 1로 설정됟나. 예를 들어 파일 읽기 에러가 발생되면 1로 설정된다.
 failbit  입력 연산이 기대하는 문자를 읽지 못하거나, 출력 연산이 기대하는 문자를 써 넣지 못하면 1로 설정된다.
 goodbit  9을 다르게 표현하는 방법이다.
 good()  스트림을 사용할 수 있으면 true를 리턴한다.(모든비트가 해제된다)
 eof()  eofbit가 설정되면 true를 리턴한다.
 bad()  badbit가 설정되면 true를 리턴한다.
 fail()  badbit나 failbit가 설정되면 true를 리턴한다.
 rdstate()  스트림 상태를 리턴한다.
 exceptions()  예외를 발생시킨 플래그를 식별하는 비트마스크를 리턴한다.
 exceptions(iostate ex)  clear()를 통해 예외를 발생시킬 상태를 설정한다. 예를들어, ex가 eofbit인 경우, clear()는 eofbit가 설정되면 예외를 발생시킨다.
 clear(iostate s) 스트림 상태를 s 로 설정한다. 여기서 s의 디폴트는 0(goodbit)이다. (rdstate() & exceptions()) != 0 이면 basic_ios::failure 예외를 발생시킨다. 
 setstate(iostate s)  clear(rdstate()|s) 를 호출한다. 이것은 스트림 상태 비트를 s에 설정된 해당 비트로 설정한다. 다른 스트림 상태 비트들은 변경되지 않는다.







상태 설정
상태 설정 중에 clear()와 setstate()는 비슷하다. 둘 다 스트림 상태를 다시 설정한다. 그러나 설정하는 방법이 다르다. clear() 메서드는 상태를 그 전달인자로 설정한다. 
clear();   <= 디폴트 전달 인자는 0을 사용하여 3개의 상태 비트은 eofbit, badbit, failbit를 모두 해제 한다. 
clear(eofbit); <= 상태를 eofbit와 동긍하게 만든다. 즉, eofbit가 설정되고 다른 두 상태 비트는 해제된다.
setstate(eofbit); <= 다른 비트에는 영향을 주지 않고, eofbit만 설정한다. failbit가 이미 설정되어 있으면 그 상태를 그대로 유지한다.

입출력과 예외
cin.exception(badbit); //badbit를 설정하여 예외를 발생시킨다.
cin.exception(badbit | eofbit); // 나중에 badbit 나 eofbit가 자중에 설정되면 예외를 발생 시킨다.


cinexcp.cpp



#include <iostream>
#include <exception>

int main(void)
{

using namespace std;
//failbit가 예외를 발생 시키게 만든다.
cin.exceptions(ios_base::failbit);
cout<<"수들을 입력하십시오:";
int sum = 0;
int input;
try{
while(cin>>input)
{
sum+=input;
}
} catch(ios_base::failure & bf)
{
cout<<bf.what()<<endl;
cout<<"앗! 실수!"<<endl;
}

cout<<"마지막으로 입력한 값 = "<<input<<endl;
cout<<"합계 = "<<sum<<endl;

cin.clear();

cin.get();
cin.get();
cin.get();

return 0;

}


어떤 스트림 상태 비트가 설정된 후에 프로그램이 입력을 더 읽을 수 있게 하려면, 스트림 상태를 good 상태로 다시 설정한다. clear() 메서드를 호출하면 된다.

while(cin>>input)
{
sum += input;
}
cout<<"마지막으로 입력한 값 = "<<input<<endl;
cout<<"합계 = "<<sum<<endl;
cout<<"새로 하나의 수를 입력하십시오: ";
cin.clear(); // 스트림 상태를 다시 설정한다.
while(!isspace(cin.get()))
continue;
cin>>input;




cin 을 fflush화 하기!!!
//루프가 잘못된 입력 때문에 종료되었다고 가정할때...
cin.clear();
while(!isspace(cin.get()))
continue;
cin.get();
// 스트림 상태를 다시 설정하는 것만으로는 충분하지 않다. 입력 루프를 종료시킨 불량 입력이 여전히 입력 큐에 남아 있기 때문에, 프로그램은 그것을 통과ㅐ야 한다. 한가지 방법은 화이트스페이스에 도달할 때까지 계속해서 문자를 읽는 것이다. isspace()함수는 전달인자가 화이트스페이스면 true를 리턴하는 cctype함수이다.
while(cin.get() != '\n')
continue;
 그렇지 않으면 그 다음 단어만이 아니라 중의 나머지를 제거할 수도 있다. 

//좀더 확실한 방법

while(cin>>input)
{
sum += input;
}
cout<<"마지막으로 입력한 값 = " <<input<<endl;
cout<<"합계 = " <<sum<<endl;
if(cin.fail() && !cin.eof()) // 불량 입력때문에 실패하면
{
cin.clear();         //스트림 상태를 다시 설정한다.
while(!isspace(cin.get()))
continue; // 불량 입력을 제거한다.
}
else                               // 그렇지 않으면 위험에서 탈출
{
cout<<"계속할 수 없습니다."<<endl;
exit(1);
}
cout<<"새로 하나의 수를 입력하십시오 : ";
cin>>input;








어떤 단일 문자 입력을 사용할 것인가?
>>, get(char &), get(void) 중 어떤 것을 사용해야 할까?????????

1. 화이트스페이스를 건너뛰는 것이 편리 하다면 >> 를 사용한다.
ex )          char ch;  cin>>ch;
2. 프로그램이 모든 문자를 검사하기를 원한다면, get() 메서드 중 하나를 사용해야 한다. 
3. get(void) 메서드의 큰 장점은 표준 C의 getchar() 와 가깝게 닮았다는 것이다. 이것은 stdio.h 대신 iostream을 사용하고, getchar()를 cin.get()으로 일괄적으로 대체하고, C의 putchar(ch)를 cout.put(ch)로 일괄 대체하면, C프로그램을 C++ 프로그램으로 변환할 수 있다는 것을 의미한다.


문자열 입력 : getline(), get(), ignore()

istream & get(char *, int, char);
istream & get(char *, int );
istream & getline(char *, int , char );
istream & getline(char *, int);
=> 제 1전달인자 : 입력 문자열을 저장할 메모리의 주소
    제 2전달인자 : 일어들일 최대 허용 문자 수보다 1만큼 큰 값(NULL문자 때문에)
    제 3 전달인자 : 입력에 구획 문자로 사용할 문자를 지정

getline()과 get()의 차이점
getline()은 입력 스트림에서 개행 문자를 읽어서 그냥 버린다. but get()은 구획 문자를 입력 큐에 그대로 남겨둔다.






//get_fun.cpp
/*

#include <iostream>
const int Limit = 255;

int main(void)
{
using namespace std;

char input[Limit];

cout << "getline()이 처리할 문자열을 입력하십시오: "<<endl;

cin.getline(input, Limit, '#');
cout<<"다음과 같이 입력하였습니다"<<endl;
cout<<input<<endl<<"1단계 완료"<<endl;


char ch;
cin.get(ch);
cout<<"다음 입력 문자는 "<<ch<<"입니다"<<endl;

if(ch != '\n')
{
cin.ignore(Limit, '\n');// 그 줄의 나머지를 읽고 버린다.

}
cout<<"get() 이 처리할 문자열을 입력하십시오:"<<endl;
cin.get(input, Limit, '#');
cout<< "다음과 같이 입력하셨습니다."<<endl;
cout<<input<<endl<<"2단계 완료"<<endl;

cin.get(ch);
cout<<"다음 입력 문자는 "<<ch<<"입니다."<<endl;


cin.clear();
while(cin.get() != '\n')
continue;
cin.get();



return 0;

}
*/


/*
getline()이 처리할 문자열을 입력하십시오:
Please pass me a #3 melon!
다음과 같이 입력하였습니다
Please pass me a
1단계 완료
다음 입력 문자는 3입니다
get() 이 처리할 문자열을 입력하십시오:
I still
want my #3 melon!
다음과 같이 입력하셨습니다.
I still
want my
2단계 완료
다음 입력 문자는 #입니다.
*/



//peeker.cpp
/*

#include <iostream>
int main(void)
{
using namespace std;
char ch;
while(cin.get(ch)) //EOF에서 종료한다.
{
if(ch != '#')
cout<<ch;
else
{
cin.putback(ch); //
break;
}
}
if(!cin.eof())
{
cin.get(ch);
cout<<endl<<ch<<"은 다음 입력 문자입니다."<<endl;
}
else
{
cout<<"파일 끝에 도달했습니다."<<endl;
exit(0);
}

while(cin.peek() != '#') //미리 엿보기
{
cin.get(ch);
cout<<ch;
}
if(!cin.eof())
{
cin.get(ch);
cout<<endl<<ch<<"은 다음 입력 문자입니다."<<endl;
}
else
cout<<"파일 끝에 도달했습니다."<<endl;

return 0;

}
*/

/*
I used a #3 pencil when I should have used a #2.
I used a
#은 다음 입력 문자입니다.
3 pencil when I should have used a
#은 다은 입력 문자입니다.
*/

// truncate.cpp -- 입력행이 길 때 get()을 사용하여 자른다.
#include <iostream>
const int SLEN = 10;
inline void eatline() { while(std::cin.get() != '\n') continue;};
int main(void)
{
using std::cin;
using std::cout;
using std::endl;

char name[SLEN];
char title[SLEN];
cout<<"이름을 입력하십시오: ";
cin.get(name, SLEN);
if(cin.peek() != '\n')
cout<<"죄송합니다. 이름란이 좁아서 "<<name<<"만 적어 넣었습니다."<<endl;
eatline();
cout<<name<<"씨! 직위를 입력하십시오: "<<endl;
cin.get(title, SLEN);
if(cin.peek() != '\n')
cout<<"직위도 뒷부분을 잘랐습니다.\n";
eatline();
cout<<"이름 : "<< name
<<"\n직위 : "<<title<<endl;

return 0;
}

/*
이름을 입력하십시오: Ella Fishsniffer
죄송합니다. 이름란이 좁아서 Ella Fish만 적어 넣었습다
Ella Fish 씨! 직위를 입력하십시오:
Executive Adjusct
직위로 뒷부분을 잘랐습니다.
이름 : Ella Fish
직위 : Executive
*/






















파일 입력과 출력






//fileio.cpp

#include <iostream>
#include <fstream>
#include <string>

inline void eatline() { while(std::cin.get() != '\n') continue;};

int main(void)
{

using namespace std;
string filename;

cout<<"새 파일을 위한 이름을 입력하십시오: ";
cin>>filename;

//새 파일을 위한 출력 스트림 객체를 fout이라는 이름으로 생성한다.
ofstream fout(filename.c_str());

fout<<"비밀 번호 노출에 주의하십시오.\n"; //파일에 기록한다.
cout<<"비밀 번호를 입력하십시오: ";
float secret;
cin>>secret;
fout<< "귀하의 비밀 번호는 "<<secret<< "입니다.\n";
fout.close(); //파일을 닫는다.

//새 파일을 위한 입력 스트림 객체를 fin 이라는 이름으로 생성한다.
ifstream fin(filename.c_str());
cout<<filename<<" 파일의 내용은 다음과 같습니다:\n";
char ch;
while(fin.get(ch))
cout<<ch;
cout << "프로그램을 종료합니다.\n";
fin.close();


eatline();
cin.get();

return 0;
}



//count.cpp

#include <iostream>
#include <fstream>
#include <cstdlib>
//#include <console.h> //맥을 위해

int main(int argc, char *argv[])
{
using namespace std;
//argv = ccommand(&argv); //매킨토시를 위해
if(argc == 1)
{
cerr<<"사용법 : "<<argv[0] <<" filename[s]\n";
exit(EXIT_FAILURE);
}
ifstream fin;
long count;
long total = 0;
char ch;

for(int file = 1; file < argc; file++)
{
fin.open(argv[file]);

if(!fin.is_open())
{
cerr<<argv[file]<<"파일을 열 수 없스니다."<<endl;
fin.clear();
continue;
}
count = 0;
while(fin.get(ch))
count++;
cout<<argv[file]<<" 파일에 들어 있는 문자 수는 "<<count<<"입니다.\n";
total += count;
fin.clear(); //일부 컴파일러에서 요구한다.
fin.close(); //파일과의 연결을 끊는다.

}
cout<<" 전체 파일에 들어 있는 문자 수는 "<<total<<"입니다.\n";

return 0;

}



파일 모드
//파일 모드는 파일을 읽을 것인지, 파일에 기록할 것인지, 아니면 파일의 뒤에 내용을 덧붙일 것인지 등 파일이 사용되는 방법을 나타낸다. 파일 이름으로 파일 스트림 객체를 초기화하거나, open() 메서드를 이용하여 스르팀을 파일에 연결시킬 때 파일 모드는 지정하는 제 2 전달인자를 사용할 수 있다.
ifstream fin("feelpass", mode1); // mode 전달인자가 있는 생성자
ofstream fout();
fout.open("feelpass", mode2); // mode 전달인자가 있는 open()

파일 모드 상수들
 상수  의미
 ios_base::in  파일을 읽기 위해 연다.
 ios_base::out  파일에 쓰기 위해 연다.
 ios_base::ate  파일을 열 때 파일 끝을 찾는다.
 ios_base::app  파일 끝에 덧 붙인다.
 ios_base::trunc  파일이 이미 존재하면 파일 내용을 비운다.
 ios_base::binary  2진 파일

ifstream의 open() 메서드와 생성자는 ios_base::in 이 디폴트 전달인자
ofstream의 open() 메서드와 생성자는 ios_base::out | ios_base::trunc 이 디폴트 전달인자


C++와 C의 파일 열기 모드
 C++모드  C모드  의미
 ios_base::in  "r"  읽기 위해 연다.
 ios_base::out  "w"  (ios_base::out | ios_base::trunc 와 같다.)
 ios_base::out | ios_base::trunc  "w" 쓰기 위해 열고, 파일이 이미 존재하면 내용을 비운다.
 ios_base::out | ios_base::app  "a"  쓰기 위해 열고, 뒷에 덧 붙인다.
 ios_base::in | ios_base::out  "r+"  읽기/쓰기 겸용으로 열고, 파일 안의 어디에나 쓸 수 잇다.
 ios_base::in | ios_base::out | ios_base::trunc  "w+"  읽기/쓰기 겸용으로 열고, 파일이 이미 존재하면 그 파일의 내용을 먼저 비운다.
 c++mode | ios_base::binary  "cmodeb"  c++mode 모드 또는 그에 상응하는 cmode와 2진 모드로 연다. 예를 들어, ios_base::in | ios_base::binary이면 "rb"가 된다.
 c++mode | ios_base:ate  "cmode"  지시된 모드로 열고, 파일의 끝으로 파일 포인터를 이동한다. C는 모드 코드 대신에 별도의 함수를 호출을 사용한다. 예를 들어, ios_base::in | ios_base::ate는 C 함수 호출 fseek(file, 0, SEEK_END)로 변역 된다.

# ios_base::ate와 ios_base::app 는 둘다 방금 연 파일의 끝으로 파일 포인터를 이동시킨다. 둘 간의 차이는 ios_base::app 모드는 파일의 끝에만 데이터를 덧 붙일 수 있는 반면에, ios_base::ate 모드는 단지 파일 포인터만 파일 끝에 위치시키는 것이다.


//append.cpp -- 파일에 정보를 덧붙인다.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> //또는 stdlib.h exit()를 사용하기 위해


inline void eatline() { while(std::cin.get() != '\n') continue;};

const char * file = "guests.txt";
int main(void)
{
using namespace std;
char ch;

//초기 내용을 화면에 표시한다.
ifstream fin;
fin.open(file);

if(fin.is_open())
{
cout<<file<<" 파일의 현재 내용은 다음과 같습니다:\n";
while(fin.get(ch))
cout<<ch;
fin.close();
}


//새로운 손님 이름들을 추가한다.
ofstream fout(file, ios_base::out | ios_base::app);
if(!fout.is_open())
{
cerr<<"출력을 위해 "<<file<<" 파일을 열 수 없습니다.\n";
exit(EXIT_FAILURE);

}

cout<<" 새로운 손님 이름들을 입력하십시오(끝내려면 빈 줄 입력):\n";
string name;
while(getline(cin,name) && name.size() > 0)
{
fout<<name<<endl;
}
fout.close();

//개정된 파일을 화면에 표시한다.
fin.clear();
fin.open(file);

if(fin.is_open())
{
cout<<file<<" 파일의 현재 내용은 다음과 같습니다:\n";
while(fin.get(ch))
cout<<ch;
fin.close();
}

eatline();
cin.get();

return 0;
}
















2진파일









//binary.cpp

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>

inline void eatline() {while(std::cin.get() != '\n') continue;}


struct planet
{
char name[20];
double poplulation;
double g;
};

const char * file = "planets.dat";

int main(void)
{
using namespace std;
planet pl;
cout<<fixed<<right;


//초기의 내용을 화면에 표시한다.
ifstream fin;
fin.open(file, ios_base::in | ios_base::binary); //2진파일
//주 : 어떤 컴파일러는 ios_base::binary 모드를 받아들이지 않는다.

if(fin.is_open())
{
cout<<file<<" 파일의 현재 내용은 다음과 같습니다:\n";
while(fin.read((char*)&pl,sizeof pl))
{
cout<<setw(20)<<pl.name<< ": "
<<setprecision(0)<<setw(12)<<pl.poplulation
<<setprecision(2)<<setw(6)<<pl.g<<endl;
}
fin.close();
}



//새로운 데이터를 추가한다.
ofstream fout(file, ios_base::out | ios_base::app | ios_base::binary);
//주 : 어떤 컴파일러는 ios_base::binary 모드를 받아들이지 않는다.
if(!fout.is_open())
{
cerr<<"출력을 위해 "<<file<<" 파일을 열 수 없습니다.\n";
exit(EXIT_FAILURE);
}
cout<<"행성의 이름을 입력하십시오(끝내려면 빈 줄 입력):\n";
cin.get(pl.name,20);
while(pl.name[0] != '\0')
{
eatline();
cout<<"행성의 인구를 입력하십시오: ";
cin>>pl.poplulation;
cout<<"행성의 중력가속도를 입력하십시오: ";
cin>>pl.g;
eatline();
fout.write((char*)&pl,sizeof(pl));
cout<<"행성의 이름을 입력하십시오(끝내려면 빈 줄 입력):\n";
cin.get(pl.name, 20);
}
fout.close();

//개정된 파일을 화면에 표시한다.
fin.clear(); //요구하지 않는 컴파일러도 있지만, 있어도 괜찮다.


fin.open(file, ios_base::in | ios_base::binary); //2진파일
//주 : 어떤 컴파일러는 ios_base::binary 모드를 받아들이지 않는다.

if(fin.is_open())
{
cout<<file<<" 파일의 현재 내용은 다음과 같습니다:\n";
while(fin.read((char*)&pl,sizeof pl))
{
cout<<setw(20)<<pl.name<< ": "
<<setprecision(0)<<setw(12)<<pl.poplulation
<<setprecision(2)<<setw(6)<<pl.g<<endl;
}
fin.close();
}

cout<<"프로그램을 종료합니다.\n";

}


















2진파일 읽고 쓰기 // 파일 포인터

fstream 클래스는 이 일을 처리하는 두가지 메서드를 상속한다. seekg()는 입력포인터를 주어진 위치로 옮긴다. seekp()는 출력 포인터를 주어진 위치로 옮긴다.

//random.cpp //2진 파일에 임의 접근
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>

const int LIM = 20;

struct planet
{
char name[20];
double population;
double g;

};

const char * file = "planets.dat";
inline void eatline(){while(std::cin.get() != '\n') continue;}

int main()
{
using namespace std;
planet pl;
cout<<fixed;

//초기의 내용을 화면에 표시한다.
fstream finout;
finout.open(file, ios_base::in | ios_base::out | ios_base::binary);

int ct = 0;
if(finout.is_open())
{
finout.seekg(0); //시작위치로 간다.
cout<<file<<" 파일의 현재 내용은 다음과 같습니다.\n";
while(finout.read((char*)&pl, sizeof(pl)))
{
cout<<ct++<<": "<<setw(LIM)<<pl.name<<": "<<setprecision(0)<<setw(12)<<pl.population<<setprecision(2)<<setw(6)<<pl.g<<endl;
}
if(finout.eof())
finout.clear();
else
{
cerr<<file<<" 파일을 읽다가 에러 발생.\n";
exit(EXIT_FAILURE);

}
}
else
{
cerr<<file<<" 파일을 열 수 없습니다. 종료. \n";
exit(EXIT_FAILURE);
}

//레코드를 수정한다.
cout<<"수정할 레코드 번호를 입력하십시오: ";
long rec;
cin>>rec;
eatline();
if(rec<0 || rec>=ct)
{
cerr<<"잘못된 레코드 번호입니다. 종료.\n";
exit(EXIT_FAILURE);

}
streampos place = rec * sizeof(pl);
finout.seekg(place);
if(finout.fail())
{
cerr<<"레코드를 찾다가 에러 발생.\n";
exit(EXIT_FAILURE);
}

finout.read((char*)&pl,sizeof(pl));
cout<<"현재 레코드의 내용:\n";
cout<<rec << ": "<<setw(LIM)<<pl.name<<": "<<setprecision(0)<<setw(12)<<pl.population<<setprecision(2)<<setw(6)<<pl.g<<endl;
if(finout.eof())
finout.clear();

cout<<"행성의 이름을 입력하시오: ";
cin.get(pl.name, LIM);
eatline();
cout<<"행성의 인구를 입력하십시오: ";
cin>>pl.population;
cout<<"행성의 중력가속도를 입력하십시오: ";
cin>>pl.g;
finout.seekp(place);
finout.write((char*)&pl,sizeof(pl))<<flush;
if(finout.fail())
{
cerr<<"쓰다가 에러 발생.\n";
exit(EXIT_FAILURE);

}

ct = 0;
finout.seekg(0); //시작위치로 간다.
cout<<file<<" 파일의 현재 내용은 다음과 같습니다.\n";
while(finout.read((char*)&pl, sizeof(pl)))
{
cout<<ct++<<": "<<setw(LIM)<<pl.name<<": "<<setprecision(0)<<setw(12)<<pl.population<<setprecision(2)<<setw(6)<<pl.g<<endl;
}
finout.close();
cout<<" 프로그램을 종료합니다.\n";
return 0;
}











인코어 형식의 지정
iostream 계열은 프로그램과 단말기 사이의 입출력을 지원한다. fstream 계열은 동일한 인터페이스를 사용하여 프로그램과 파일 사이의 입출력을 지원한다. 또하 C++의 라이브러리는 sstream 계열을 제공한다. sstream 계열은 동일한 인터페이스를 사용하여 프로그램과 string 객체 사이의 입출력을 제공한다. 즉, cout과 함께 사용한 ostream 메서드들을, 형식이 지정된 정보를 string 객체에 기록하는데 사용할 수 있다. 그리고 getline()과 같은 istream 메서드를 string 객체로부터 정보를 읽는 데 사용할 수 있다. string 객체로부터 형식이 지정된 정보를 읽거나, string 객체에 형식이 지정된 정보를 기록하는 과정을 인코어 형식의 지정이라 한다. 

ostringstream outstr;
double price = 281.00;
char * ps = " for a copy of the ISO/EIC C++ standard!";
outstr.precision(2);
outstr<<fixed;
outstr<<"Pay only $" << price<<ps<<endl;
string mesg = outstr.str();

//strout.cpp -- 인코어 형식의 지정(출력)
#include <iostream>
#include <sstream>
#include <string>

int main(void)
{
using namespace std;
ostringstream outstr; //string 스트림을 관리한ㄷ.
string hdisk;
cout<"하드웨어의 모델명이 무엇입니까? ";
getline(cin,hdisk);
int cap;
cout<<"하드디스크의 용량이 몇 GB입니까? ";
cin>>cap;
//형식이 지정된 정보를 string 스트림에 써 넣는다.
outstr<<hdisk<<" 하드디스크의 용량은 "<<cap<<" GB입니다.\n";
string result = outstr.str();
cout<<result;

return 0;
}


//strin.cpp -- char 형의 배열로부터 형식을 지정하여 읽는다.
#include <iostream>
#include <sstream>
#include <string>

int main(void)
{
using namespace std;
string lit = "길섶 민들레 꽃씨대롱 방울로 부풀어 여윈 목 아프게 빼어 들고 아가씨 실어 나를 바람 기다리누나.";
istringstream instr(lit); //입력버퍼를 사용한다.
string word;
while(instr>>word)
cout<<word<<endl;
return 0;
}