프로그래밍 노트

[WIN32 SDK] 파일 읽고 쓰기 본문

Win32 SDK 초보

[WIN32 SDK] 파일 읽고 쓰기

띠리 2008. 5. 14. 17:39

파일에는 텍스트 파일과 바이너리 파일의 두종류가 있다.
텍스트 파일은 문자 정보로 되어있는 파일이고 윈도우즈에 있는 메모장같은
텍스트 에디터로 편집할 수 있는 파일이다.
에디터로 열어 보면 어떤 데이터가 들어있는지 볼 수 있다.
이에 반해 바이너리 파일은 바이너리, 2진수의 데이터가 나열되어있는 파일로
16진수로 변환하여 덤프 표시를 해주는 프로그램을 사용해서 볼수 있다.
그렇게 본다고 해도 사람이 이해할 수 있는 데이터인 경우도 있지만
주로 이해할 수 없는 데이터들일 것이다.

예를 들면 C언어의 소스 파일은 텍스트 파일이지만 소스 파일을 컴파일/링크하여
생기는 오브젝트 파일(*.obj파일)이나 실행 파일은 바이너리 파일이다.
이런 파일을 텍스트 에디터로 읽어봐도 무슨 의미인지 알 수 없다.
그러나 컴퓨터에게 있어서는 의미가 있는 2진수의 나열이기 때문에 소스 파일에
짜여진 처리를 실행 형식의 파일에서 읽어서 실행할 수 있다.
그 외에도 그림 데이터, 음악 데이터나 워드로 만든 문서 파일도 서식 정보를 가지고 있는
바이너리 파일이다.

텍스트 파일과 바이너리 파일외에도 데이터의 기록하는 방식에 따라서
시퀀셜 파일이나 랜덤 파일로 나누어진다.
C에서는 각각의 기록 방식이 틀리지는 않지만 파일을 억세스하는데 있어서
시퀀셜 억세스와 랜덤 억세스가 있다 시퀀셜 억세스는 파일의 처음부터
순차적으로 읽는 방법이다. 이에반해 램덤 억세스는 파일의 임의의 위치부터
읽거나 쓸수있는 방법으로 하드디스크 억세스와 비슷하다.

================================================================================

파일을 열고 닫기(fopen, fclose)

파일의 데이터를 읽고 쓰기 위해서는 파일을 열어야된다.
예제 1은 파일을 읽어서 파일의 내용을 표시하고 파일을 닫는다.

#include  <stdio.h>

int main()
{
    FILE *fp;
    int nChar;

    if((fp = fopen("test.txt", "r")) == NULL)
        return(1);

 while((nChar = fgetc(fp)) != EOF){
        putchar(nChar);
 }

 fclose(fp);
 return(0);
}

예제 1 텍스트 파일을 열어 파일의 내용을 표시하고 닫는 예제



함수명
형식
처리내용
fopen FILE *fopen(
    const char *filename
    const char *mode);
filename의 파일을 열어서 FILE구조체에 포인터를
반환한다. mode는 테이블2 참조
fclose int fclose(FILE *fp) fopen에서 연 파일의 포인터(fp)로 파일을 닫는다.
테이블 1 파일 열고 닫는 함수


모드
의미
r 읽기 전용으로 파일 열기.
기존 파일이 없으면 에러를 반환
w 쓰기 전용으로 파일 열기.
기존 파일이 있으면 덮어쓰고 기존 파일이 없으면 새로 작성
a 덧붙여 쓰기로 파일 열기
기존 파일이 있으면 파일 끝에서부터 데이터 추가
기존 파일이 없으면 새로 작성
테이블 2 파일 열기 모드

+가 붙으면 r+, w+, a+가 붙으면 읽기, 쓰기 모두가 가능하게 된다.

fopen 함수는 파일 열기에 성공하며 파일의 포인터를 반환한다. 파일 포인터는 FILE구조체의 포인터이다. FILE구조체에의 포인터 fp에는 그 파일에 억세스하기 위해 필요한 정보에의 참조가 설정되어있다. 파일이 없거나해서 파일 열기에 실패하면 fopen 함수는 NULL을 반환한다.

fgetc함수는 파일로부터 한 문자씩 읽어 들인다. EOF를 반환할 때까지 한 문자씩 읽는 것을 반복한다. putchar 함수로 표준 출력으로 표시한다. 또 파일은 사용이 끝나면 파일을 닫아야된다. 파일 포인터 fp를 닫는다.


함수명
형식
처리내용
fgetc int fgetc(FILE *fp); 파일에서 한 문자씩 읽고 일어들인 문자를 반복한다.
파일의 끝이나 에러일 경우에 EOF를 반환한다.
fputc int fputc(int c, FILE *fp); 파일에 한 문자씩 쓰고, 쓴 문자를 반환한다. 에러일 경우에 EOF를 반환한다.
테이블 3 문자 입출력에 관한 함수


  예제2에서는 fpi, fpo로 입력과 출력용 파일 포인터를 선언하고 있다 또 파일명을 scanf 함수로 받아서 입력된 파일명의 파일을 열 수없는 경우 putchar에서 "\a"로 비프음을 울리는 에러 처리로 보내어져 메세지를 보여주고 exit함수로 프로그램을 종료한다. 실행되면 한 문자씩 읽어와서 한 문자씩 써서 파일의 내용을 다른 파일에 카피한다.


#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fpi, *fpo;
    char fname[2][64];
    int nChar;

    printf("입력 파일명 :");
    scanf("%s", fname[0]);
    printf("출력 파일명 :");
    scanf("%s", fname[1]);

    if((fpi = fopen(fname[0], "r")) == NULL){
        putchar('\a');
        printf("\n %s 파일을 열지 못함\n", fname[0]);
        exit(1);
    }
    if((fpo = fopen(fname[1], "w")) == NULL){
        putchar('\a');
        printf("\n %s 파일을 열지 못함\n", fname[1]);
        exit(1);
    }
    while((nChar = fgetc(fpi)) != EOF){
        fputc(nChar, fpo);
    }

    fclose(fpi);
    fclose(fpo);
    return(0);
}

예제 2 텍스트 파일을 내용을 카피하는 예제


예제3에서 파일을 열어서 fgets로 라인으로 읽고 puts로 라인을 출력한다.
파일이름은 커맨드 라인의 첫번째 인수로 메인 함수에서 넘겨준다.
(디버그할 때 명령 인수를 넘기는 방법은 프로젝트 메뉴의 속성을 선택하고
트리뷰의 구성 속성의 디버깅을 선택한 후, 명령 인수에 읽어올 파일명을 입력한다.)

#include  <stdio.h>
#include  <stdlib.h>
#include  <string.h>

int main(int argc, char *argv[])
{
    FILE *fp;
    char szLine[256];

    if(argc < 2)
        exit(1);

    if((fp = fopen(argv[1], "r")) == NULL)
        exit(1);

    while(fgets(szLine, 256, fp) != NULL){
        szLine[strlen(szLine) - 1] = '\0';
        puts(szLine);
    }
    fclose(fp);
    return(0);
}

예제 3 파일을 열어 라인으로 읽고 라인으로 출력하는 예제

예제 3에서 밑의 행이 들어간 이유는 행을 읽어오고 puts를 이용하여 출력할 때 "\0"이 "\n"으로 바뀌어 개행이 됨으로 두줄이 되기 때문에 밑의 방법을 이용하여 2줄씩 띄어지는 것을 방지한다.
   szLine[strlen(szLine) - 1] = '\0';
fgets로 읽어온 한 행 데이터
h a h a \n \0
puts로 출력                                ↓
h a h a \n \n

puts함수로 행을 출력하면 \0이
\n으로 바뀌어 2줄씩 띄어짐
fgets로 읽어온 한 행 데이터
h a h a \n \0
szLine[strlen(szLine) - 1] = '\0';
h a h a \0 \0
puts로 출력                      ↓
h a h a \n

함수명
형식
처리내용
fgets char *fgets(char * str, int n, FILE *fp); 파일에서 한 행씩 읽어 들인다. n-1개의 문자 문자의 개행 문자를 읽는 시점에서 종료한다.
파일의 끝이나 에러일 경우에 NULL을 반환한다.
fputs int fputs(const char *str, FILE *fp); 파일에서 1행씩 출력하고 정상일 때 양수값을 반환한다. 에러일 경우에 EOF를 반환한다.
테이블 4 행단위 입출력에 관한 함수


표준 입력, 표준 출력, 표준 에러 출력 이것들도 파일이다.

파일이라는 것은 열어서 쓰거나 반드시 닫아야 된다. 파일 이외에도 이렇게 반드시 열고 닫아야되는 것이 세가지 있다. 표준 입력, 표준 출력, 표준 에러 출력이라 불리는 파일들이다.

밑의 그림과 같이 표준 입력(stdin)은 키보드로 표준 출력(stdout)과 표준 에러 출력(stderr)은 디스플레이에 설정된다. 키보드나 디스플레이가 파일이라는 것은 왠지 느낌이 안 와닿을 수 있다. 하지만 워낙 UNIX계열의 OS개발을 위해 만들어진 C언어에서는 키보드나 디스플레이 등의 주변 기기도 파일 취급을 한다.

사용자 삽입 이미지

  fputs(szLine, stdout);

위와같이 하면 출력할 곳을 stdout(표준 출력)으로 변경하여 실행하면 넘겨진 문자열을 화면에 표시한다. 결국 표준 출력도 파일과 같이 취급할 수 있다. 표준 입력, 표준 출력, 표준 에러 출력은 프로그램의 시작할 때 자동적으로 열리고 프로그램이 종료될 때 자동으로 파일이 자동으로 닫친다고 생각하면 된다.

C언어에서는 표준 입력뿐 아니라 모든 파일을 읽고 쓸 경우에는 버퍼를 사용하여 스트림 입출력을 행한다. 스트림 입출력에서는 함수가 직접 파일을 억세스하지않고 사이에 버퍼를 통하여 입출력을 한다. 프로그램은 버퍼로부터 읽고 버퍼에 쓴다. 버퍼가 비면 OS는 자동적으로 파일로 부터 읽어온다. 버퍼가 가득차면 버퍼로 부터 파일에 씌여지게 된다. 이 원리에 의해 C언어에서는 효율적으로 파일에 억세스할 수 있다.


서식을 붙이는 함수

표준 입출력에서 서식을 붙여서 입출력할 수 있다.

함수명
형식
처리내용
fscanf int fscanf(FILE *fp, const char *format, ...); 서식 format에 따라서 파일로 부터 인수에 데이터를 저장한다. 파일 엔드나 에러의 경우 EOF을 반환한다.
fprintf int fprintf(FILE *fp, const char *format, ...); 서식 format에 따라서 파일에 데이터를 출력하고 출력된 바이트 수를 반환한다. 에러의 경우는 EOF를 반환한다.
테이블 5 서식 입출력에 관한 함수

fscanf와 fprintf 함수를 사용하는 예제5는 테스트 파일을 행 단위로 읽어 행번호를 붙여서 파일을 출력하는 프로그램이다. fprintf 함수로 출력 파일에 서식을 붙여서 저장한다. 파일명의 입력에도 파일이 아니라 stdin(표준 입력 : 키보드)로 부터 읽어오게 되어있다. 오픈 에러가 발생했을 때는 fprintf 함수의 인수에 stderr(표준 에러 출력)을 지정하여 도스창에 에러를 표시한다.


#include  <stdio.h>
#include  <stdlib.h>

int main()
{
    FILE *fpi;
    FILE *fpo;
    char szFilei[64];
    char szFileo[64];
    char szBuff[256];
    unsigned int nLines = 0;

    printf("입력 파일명 입력 : ");
    fscanf(stdin, "%s", szFilei);

    if((fpi = fopen(szFilei, "r")) == NULL){
        putchar('\a');
        fprintf(stderr, "\n %s 를 열 수 없습니다.\n", szFilei);
        exit(1);
    }
    printf("출력 파일명 입력 : ");
    fscanf(stdin, "%s", szFileo);

    if((fpo = fopen(szFileo, "w")) == NULL){
        putchar('\a');
        fprintf(stderr, "\n %s 를 열 수 없습니다.\n", szFileo);
        exit(1);
    }

    while(fgets(szBuff, 256, fpi) != NULL){
        fprintf(fpo, "%5d: %s", ++nLines, szBuff);
    }
    fclose(fpi);
    fclose(fpo);
    return(0);
}

예제 4 텍스트 파일을 열어 행 번호를 붙여 다른 파일로 출력하는 예제



Comments