• 파일은 모든 데이터를 연속된 바이트 형태로 저장한다.
• 파일을 사용하기 위해서는 반드시 파일 열기 fopen()를 먼저 해야 하며 파일 열기를 하면 FILE 구조체에 대한 포인터가 리턴된다.
• FILE 포인터는 열린 파일을 나타낸다.
• fgetc() 함수와 fputc() 함수를 사용하여 파일에 문자 단위 입출력을 할 수 있다.
• fgets() 함수와 fputs() 함수를 이용하여 텍스트 파일에서 한 줄씩 읽거나 쓸 수 있다.
• fread()와 fwrite() 함수는 한 번에 일정한 크기의 데이터를 파일에 읽거나 쓴다.
• 열린 파일에서 다음 읽거나 쓸 파일 내 위치를 현재 파일 위치라고 하며 파일 위치 포인터가 그 파일의 현재 파일 위치를 가리키고 있다.
• fseek() 함수는 현재 파일 위치를 지정한 위치로 이동시킨다.
C 프로그램에서 파일이 필요한 이유
: 변수에 저장된 정보들은 실행이 끝나면 모두 사리지지만, 파일에 기록하면 정보를 영구적으로 저장할수 있기 때문
유닉스 파일
: 모든 데이터를 연속된 바이트 형태로 저장한다.
ex)
FILE *fp;
fp = fopen("~/sp/text.txt","r");
if(fp == NULL)
{
printf("파일 열기 오류\n");
}
파일 입출력 : 다양한 파일 입출력 함수 사용
파일 닫기 : fclose() 사용
-> close() 시스템호출
닫기에 성공하면 0, 오류일 때는 EOF( -1)를 리턴함.
실행방법 : fclose(fp);
fgetc() 함수 : 파일에 문자단위 입력
fputc() 함수 : 파일에 문자단위 출력
int fgetc(FILE *fp)
- getc,fgetc 함수는 fp가 지정한 파일에서 한 문자를 읽어서 리턴
int fputc(int c, FILE *fp)
- putc,fputc 함수는 파일에 한 문자씩 출력하는 함수
ex1) cat.c
#include <stdio.h>
/* 텍스트 파일 내용을 표준출력에 프린트 */
int main(int argc, char *argv[])
{
FILE *fp;
int c;
if (argc < 2)
fp = stdin; // 명령줄 인수가 없으면 표준입력 사용
else fp = fopen(argv[1],"r"); // 읽기 전용으로 파일 열기
c = getc(fp); // 파일로부터 문자 읽기
while (c != EOF)
{
putc(c, stdout); // 읽은 문자를 표준출력에 출력
c = getc(fp); // 파일로부터 문자 읽기
}
fclose(fp);
return 0;
}
ex2) copy.c
#include <stdio.h>
int main(int argc, char* argv[])
{
char c;
FILE *fp1, *fp2;
if (argc!=3)
{
fprintf(stderr,"How to use : %s FILE1 FILE2\n",argv[0]);
return 1;
}
// 첫번째 파일 읽기모드로 오픈
fp1= fopen(argv[1],"r");
// 파일열기 실패시 오류메시지 출력
if(fp1 == NULL)
{
fprintf(stderr,"Open %s error!\n",argv[1]);
return 2;
}
// 두번째 파일 쓰기모드로 오픈
fp2 = fopen(argv[2], "w");
// 내용복사
while((c= fgetc(fp1))!=EOF)
{
fputc(c,fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
int feof(FILE *fp)
: 파일 포인터 fp 가 파일의 끝을 탐지하면 0이 아닌 값을 리턴하고 파일 끝이면 0리턴
int fflush(FILE *fp)
: 아직 기록되지 않고 버퍼에 남아있는 데이터를 fp가 가리키는 출력파일에 보낸다.
버퍼 비우기 기능 수행함수
ex) line.c
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 80
int main(int argc, char* argv[])
{
FILE *fp;
int line = 0;
char buffer[MAXLINE];
if(argc!=2)
{
fprintf(stderr, "사용법:line 파일이름\n");
exit(1);
}
if( (fp = fopen(argv[1],"r")) ==NULL)
{
fprintf(stderr, "파일 열기 error \n");
exit(2);
}
while(fgets(buffer,MAXLINE,fp)!=NULL)
{
line++;
printf("%3d %s", line,buffer);
}
fclose(fp);
return 0;
}
fprintf() 함수
: printf() 함수와 같은 방법으로 파일에 데이터를 출력 할 수 있다.
fscanf() 함수
: scanf() 함수와 같은 방법으로 파일로부터 데이터를 읽어 들일 수 있다.
ex1) fprintf.c
#include <stdio.h>
#include "student.h"
/* 학생 정보를 읽어 텍스트 파일에 저장한다. */
int main(int argc, char* argv[])
{
struct student rec;
FILE* fp;
if (argc != 2) {
fprintf(stderr, "사용법: %s 파일이름\n", argv[0]);
return 1;
}
// argv[1]를 쓰기모드로 오픈
fp = fopen(argv[1],"w");
printf("%-9s %-7s %-4s\n","학번", "이름", "점수");
// 학번 이름 점수 입력받고
while(scanf("%d %s %d", &rec.id, rec.name, &rec.score)==3)
// fp에 저장
fprintf(fp,"%10d %6s %6d\n",rec.id,rec.name,rec.score);
fclose(fp);
return 0;
}
ex2 ) fscan.c
#include <stdio.h>
#include "student.h"
/* 텍스트 파일에서 학생 정보를 읽어 프린트한다. */
int main(int argc, char* argv[]) {
struct student rec;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "사용법: %s 파일이름\n", argv[0]);
return 1;
}
fp = fopen(argv[1], "r");
printf("%-9s %-7s %-4s\n", "학번", "이름", "점수");
while (fscanf(fp,"%d %s %d", &rec.id, rec.name, &rec.score)==3)
printf("%10d %6s %6d\n", rec.id, rec.name, rec.score);
fclose(fp);
return 0;
}
이진 파일은
fopen() : 이진 파일 열기
fread()와 fwrite()
: 한번에 일정한 크기의 데이터를 파일에 읽거나 쓰기 위한 입출력 함수
int fread(void buf, int size, int n, FILE fp);
: fp가 가리키는 파일에서 size 크기의 블록(연속될 바이트)을 n개 읽어서 버퍼 포인터 buf가 가리키는 곳에 저장하고 읽어온 블록의 개수를 리턴한다.
int fwrite(const void buf, int size, int n, FILE fp);
: 파일 포인터 fp가 지정한 파일을 버퍼 buf에 저장되어 있는 size크기의 블록(연속된 바이트)을 n개 기록하고 성공적으로 출력한 블록 개수를 리턴한다.
기본 아이디어
: 어떤 자료형의 데이터이던지 그 데이터를 연속된 바이트로 해석해서 파일에 저장한다.
: 파일에 저장된 데이터를 연속된 바이트 형태로 읽어서 원래 변수에 순서대로 저장하여 원래 데이터를 그대로 복원
ex) rec저장
struct student rec;
FILE *fp = fopen("stfile","wb");
...
fwrite(&rec,sizeof(rec),1,fp);
ex) stcreate1.c
#include <stdio.h>
#include "student.h"
int main(int argc, char* argv[])
{
struct student rec;
FILE *fp;
if (argc != 2) {
fprintf(stderr, "사용법: %s 파일이름\n",argv[0]);
exit(1);
}
// argv[1]을 wb-> 읽기+쓰기모드로 오픈
fp = fopen(argv[1], "wb");
printf("%-9s %-7s %-4s\n", "학번", "이름", "점수");
// 정보 입력받고
while (scanf("%d %s %d", &rec.id, rec.name, &rec.score) == 3)
// rec버퍼에 기록한 내용을 파일 포인터 fp가 가리키는곳에 기록
fwrite(&rec, sizeof(rec), 1, fp);
fclose(fp);
exit(0);
}
현재 파일 위치
: 열린 파일에서 다음 읽거나 기록할 파일 내 위치
파일 위치 포인터
: 시스템 내에 그 파일의 현재 파일 위치를 저장
디스크 I/O 수행의 최소화
-> read(),write() 함수 호출의 최소화
최적의 크기 단위로 I/O 수행
시스템 성능 향상
ex)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _IO_UNBUFFERED 2
#define _IO_LINE_BUF 0x200
int main(int argc, char* argv[])
{
FILE *fp;
if(!strcmp(argv[1],"stdin")) // 표준 입력
{
fp = stdin;
printf(" 한 글자 입력 : ");
if(getchar() == EOF) perror("getchar");
}
else if(!strcmp(argv[1],"stdout")) // 표준 출력
{
fp = stdout;
}
else if(!strcmp(argv[1],"stderr")) // 표준 에러
{
fp = stderr;
}
else if( (fp= fopen(argv[1],"r")) == NULL)
{
perror("fopen");
exit(1);
}
else if(getc(fp)==EOF) perror("getc");
printf("스트림 = %s ",argv[1]);
if(fp-> _flags & _IO_UNBUFFERED)
{
printf("버퍼 미사용");
}
else if( fp->_flags & _IO_LINE_BUF)
{
printf("줄 버퍼 사용");
}
else
{
printf("완전 버퍼 사용");
}
printf(", 버퍼 크기 = %d\n",fp->_IO_buf_end - fp->_IO_buf_base);
exit(0);
}
#include <stdio.h>
void setbuf (FILE *fp, char *buf );
int setvbuf (FILE *fp, char *buf, int mode, size_t size );
: 버퍼 사용을 on/off 할 수 있다.
: buf 가 NULL이면 버퍼 미사용 방식
: buf가 BUFSIZ 크기의 공간을 가리키면 완전/줄 버퍼 방식
터미널 장치면 줄버퍼 방식
그렇지않으면 완전 버퍼 방식
: 버퍼 사용방법을 변경
성공하면 0, 실패하면 Non-zero 값 리턴
mode :
_IOFBF : 완전버퍼방식
_IOLBF : 줄버퍼 방식
_IONBF : 버퍼 미사용 방식
만약에 mode가 _IONBF 이면 buf와 size는 무시됨.
만약에 mode가 _IOFBF or _IOLBF 이고
buf 가 NULL 이면 라이브러리가 알아서 적당한 크기 할당 사용
buf가 NULL이 아니면 buf에서 size만큼의 공간 사용