파일과 스트림


구현한 프로그램에서 데이터를 불러올때, 프로그램과 참조할 데이터 사이의 데이터가 이동할 수 있는 다리를 스트림이라한다.


fopen 함수호출을 통한 스트림형성과 FILE 구조체


#include<stdio.h>

FILE * fopen (const char * filename, const char * mode); // 성공시 해당파일의 FILE 구조체 변수의 주소값 , 실패시 NULL포인터 반환


FILE 구조체의 포인터는 파일을 가리키기 위한 용도로 사용된다. 즉, 이 포인터를 이용해서 파일에 데이터를 저장하거나 파일에 저장된 데이터를 읽게된다.


입력스트림과 출력스트림의 형석


FILE * fp1 = fopen ("data.txt","wt"); // 출력스트림, 파일 data.txt와 스트림을 형성하되 , wt 모드로 스트림을 형성

FILE * fp2 = fopen ("data.txt","rt"); // 입력스트림, 파일 data.txt와 스트림을 형성하되 , rt 모드로 스트림을 형성

FILE * fp3 = fopen ("C:\\Project\\data.txt","wt"); // 출력파일이 생성될 위치를 지정할 수 있다.


if(fp1=NULL) // 파일오픈이 정상적으로 됐는지 검사

{

printf("파일오픈실패!\n"); 

return -1; // 비정상적인종료일때 -1값반환

fputc('A',fp1); // 출력스트림 fp1을통해 data.txt에 A 문자 출력

int ch = fgetc(fp2); // 입력스트림 fp2를통해 data.txt로부터 A값을 불러옴


스트림의 소멸을 요청하는 fclose 함수


#include <stdio.h>

int fclose(FILE * stream); // 성공시 0 , 실패시 EOF 반환


fclose함수의 호출을통해 개방되었던 파일을 닫아줘야하는 이유


운영체제가 할당한 자원의 반환

버퍼링 되었던 데이터의 출력 // 운영체제가 정해놓은 버퍼링방식에따라 파일저장하는때가 다르기때문에 , fclose함수로 데이터를 출력해주는게좋다.


스트림을 종료하지않고 버퍼를 비울때는 fflush 함수


#include<stdio.h>

int fflush( FILE * stream); // 함수호출 성공시 0 , 실패시 EOF 반환


파일의 개방모드


스트림을 구분하는 기준1 : 읽기위한스트림, 쓰기위한스트림


모드 r : 읽기가능 , 파일없을시 에러출력

모드 w : 쓰기가능 , 파일없을시 파일생성

모드 a : 파일의끝에 덧붙여쓰기가능 , 파일없을시 파일생성

모드 r+ : 읽기/쓰기가능 , 파일없을시 에러출력

모드 w+ : 읽기/쓰기가능 , 파일없을시 파일생성

모드 a+ : 읽기/덧붙여쓰기가능 , 파일없을시 파일생성

//웬만하면 r , w , a 를 사용하여 입력스트림과 출력스트림을 따로 생성해 사용하는것이 좋다.


스트림을 구분하는 기준2 : 텍스트모드와 바이너리모드


사람이 인식할수 있는 문자를 담고있는 파일을 가리켜 텍스트파일이라고 하며 , 그 이외에 컴퓨터가 인식할 수 있는 데이터를 파일을가리켜 바이너리파일이라고 한다. 이때 , 개행( \n)이 C언어에서만의 개행표시인데, 이것을 텍스트모드로 개방할때는 , 개행을 각 환경에 맞는 개행표시로 변환해준다. 바이너리모드는 개행을 변환하지않는다.


텍스트 모드


rt , wt , at , r+t , w+t , a+t 


바이너리모드


rb , wb , ab , r+b , w+b , a+b


파일 입출력함수


int fputc(int c,FILE * stream); // 문자 출력

int fgetc(FILE * stream); // 문자입력

int fputs(const char * s , FILE * stream ); // 문자열 출력

char * fgets(char * s , int n , FILE * steam); // 문자열 입력


ex)

char str[30];

FILE * fp = fopen("simple.txt","wt");

if(fp == NULL) // fopen 함수는 파일오픈실패시 NULL반환

{

puts("파일오픈실패!\n");

return -1;

}

fputs("MY NAME IS HONG\n",fp);  //문자열을 simple.txt 파일에 출력할때 , 개행키워드(\n)가 포함되었기때문에 txt파일로 파일을 개방해야한다. 또한, 파일에 문자열을 출력할때는 널문자가 포함되지않기때문에 , 개행키워드가(\n) 문자열을 구분하는 기준이된다.

fgets(str,sizeof(str),fp);

printf("%s",str); // MY NAME IS HONG\n 출력


파일의 끝을 확인하는 함수 : feof


#include <stdio.h>

int feof(FILE *stream); // 파일의 끝에 도달한경우 0이 아닌값 반환


ex)


FILE * src  = fopen("src.txt","rt");

FILE * des = fopen("des.txt","wt");


while ( fgets(str,sizeof(str),src)!=NULL)//fgets 함수는 읽을 데이터가 없을때 NULL을 반환한다

//or while(fgetc(n,src) != EOF) // fgetc함수는 읽을데이터가없을때 EOF반환

{

fputs(str,des);

}


if(feof != 0)

printf("파일복사성공!\n");

else

puts("파일복사실패!\n");

fclose(src);

fclose(des);


바이너리 데이터의 입출력 : fread , fwrite


#include<stdio.h>

size_t fread(void * buffer,size_t size , size_count,FILE* stream);// 성공시 전달인자 count, 실패 또는 끝 도달시 count보다 작은값 반환


ex)

int buf[12];

fread((void *)buf,sizeof(int),12,fp);//sizeof(int) 크기의 데이터 12개를 fp로부터 읽어들여서 buf 에 저장하라


#include<stdio.h>

size_t fwrite(const void * buffer,size_t size ,size_t count , FILE * stream);//성공시 전달인자 count  ,실패시 count 보다 작은 값 반환


ex)

int buf[7]={1,2,3,4,5,6,7};

fwrite((void*)buf,sizeof(int),sizeof(buf)/sizeof(int),fp); // sizeof(int)크기의 데이터 sizeof(buf)/sizeof(int)개를 fp로 출력하라


텍스트 데이터와 바이너리 데이터 동시에 입출력하기


서식에 따른 데이터 입출력 : fprintf , fscanf


fprintf의 사용법

ex)

char name[10]="홍길동";

char sex = 'M';

int age =24;

fprintf(fp,"%s %c %d",name,sex,age); // fp가 첫번째 전달인자 , fprintf 함수를 통해 "홍길동 M 24" 라는 문자열이 만들어지고 , 이렇게 만들어진 문자열이 첫번째 전달인자가 가리키는 파일에 저장된다. 즉 , 텍스트데이터와 바이너리데이터를 하나의 문자열로 묶어서 저장하는셈이다.

scanf("%s %c %d",name,&sex,&age);

getchar(); // scanf함수는 \n을 읽어들이지않고 입력버퍼에 남겨두기때문에 getchar();함수를 이용해 \n을 소멸시켜줘야한다

fprintf(fp,"%s %c %d",name,sex,age);

fclose(fp);// fp스트림 소멸


fscanf의 사용법 

fscanf 함수는 파일의 끝에 도달하거나 오류가 발생하면 EOF 를 반환한다


ex)

int ret;

char name[10];

char sex;

int age;

FILE * fp =fopen("friend.txt","rt");

while(1)

{

ret = fscanf(fp,"%s %c %d",name,&sex,&age); 

if(ret ==EOF) // ret 값이 EOF라면 파일의 끝 도달 혹은 오류발생

break;

printf("%s %c %d",name,sex,age);

}

fclose (fp);


텍스트와 바이너리 데이터의 집합체인 구조체변수의 출력


구조체변수를 하나의 바이너리데이터로 인식하고 처리한다 // fread 함수 혹은 fwrite 함수를 이용한다

ex)

Friend myfriend1;

Friend myfriend2;

FILE * fp;

fp=fopen("friend.bin","wb");

...

fwrite((void*)&friend1,sizeof(myfriend1),1,fp); // myfriend1에서 sizeof(myfriend1)만큼의 데이터를 1번 fp 스트림을통해 출력

fclose(fp)

fp=fopen("friend.bin","rb");

fread((void *)&myfriend2,sizeof(myfriend2),1,fp); // myfriend2 에 sizeof(myfriend2 ) 만큼의 데이터를 1번 fp 스트림을 통해 입력


임의 접근을 통한 '파일 위치 지시자'의 이동


FILE 구조체의 멤버중 파일의 위치정보를 저장하고있는 멤버가있는데, 이 멤버의 값은 fgets,fputs,fread,fwrite와 같은 함수가 호출 될 때마다 참조 및 갱신되며, 이 멤버가 가리키는 위치를 시작으로 문자열을 읽어들이게된다. 이 멤버를 가리켜 '파일위치 지시자'라고 부른다. 파일위치 지시자는 처음 파일이 개방되면 무조건 파일의 맨 앞부분을 가르킨다.


파일위치 지시자의 이동 : fseek


#include<stdio.h>

int fseek(FILE * stream, long offset, int wherefrom); // 성공시 0 , 실패시 0 이아닌값을 반환

// stream 으로 전달된 파일위치지시자를 wehrefrom에서부터 offset 바이트만큼 이동시켜라

매개변수 wherefrome이 

SEEK_SET 이라면 파일위치지시자는 파일 맨앞에서부터 이동을시작

SEEK_CUR이라면 파일위치지시자는 현재위치에서부터 이동을 시작

SEEK_END이라면 파일위치지시자는 파일 맨뒤에서부터 이동을시작 // 이때 , 파일의 끝 (EOF)에서부터 이동을시작

//offset에는 양의 정수뿐만아니라 음의정수도 전달될 수 있다. (음의정수 전달시 앞으로 , 양의정수전달시 뒤로 이동)


현재 파일위치지시자의 위치 : ftell


#include< stdio.h>

long ftell(FILE * stream); //파일위치지시자의 위치정보 반환



+ Recent posts