블로그 이미지
Kanais
Researcher & Developer 퍼즐을 완성하려면 퍼즐 조각들을 하나 둘씩 맞춰나가야 한다. 인생의 퍼즐 조각들을 하나 둘씩 맞춰나가다 보면 인생이란 퍼즐도 완성되는 날이 오려나...?

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

05-02 02:59

Recent Post

Recent Comment

Recent Trackback

Archive

2015. 4. 16. 13:24 Programming/C/C++



출처 : http://www.cworldlab.com/CandCplus/c/c-10.htm
참고 : http://weezzle.net/1611

작성날짜 : 2012-01-06

C에는 많은 파일 입출력 표준함수가 존재한다.  파일 입출력 함수 중 사용 빈도가 높은 함수에 대해 설명한다.   이곳에서 설명하는 함수만 사용해도 웬만한 파일 입출력 프로그램은 손쉽게 작성할 수 있다.


파일 열기, 닫기 | 입출력 | 입출력 위치 제어 | 블록 입출력


파일 열기, 닫기

파일을 사용하려면 fopen() 함수로 파일을 열어주어야 하며, 파일 사용이 끝나면 fclose() 함수로 파일을 닫아 주어야 한다.

(1) fopen() : 파일을 연다

원   형   FILE *fopen(char *filename, char *mode)A

기   능   파일 경로가 filename인 파일을 mode 상태로 연다.

함수값    열려진 파일에 할당된 FILE형 구조체를 가리키는 포인터,   파일을 열지 못했으면(오류가 발생했으면) 0(NULL).

(2) mode 문자열

fopen() 함수의 mode에는 다음 문자가 결합된 문자열을 사용한다.
 

문자

파일이 열려지는 상태

입출력 위치

r

읽기전용(Read only). 쓰기는 불가능

파일시작

w

파일을 새로 생성하고 쓰기 전용으로 연다(Write only).

파일 시작

a

추가 쓰기용(Append)

파일 끝

+

r 또는 w, a와 함께 사용하며 해당 상태로『입출력 겸용』으로 연다.

t

텍스트 방식으로 연다(내정값).

b

이진 방식으로 연다.

예   제    fp = fopen( ... , "r");

              파일을 읽기전용으로 연다.  이 파일에 대해서 쓰기(출력)는 불가능.   파일은 텍스트 모우드 상태로 열려진다.

              fp = fopen( ... , "r+");
              
              파일을 입출력 겸용으로 연다.  열려지는 방식은 텍스트 방식.

              fp = fopen( ... , "r+b");

              파일을 입출력 겸용(r+), 이진 방식(b)으로 연다.

(3) 텍스트 방식과 이진 방식

다른 것은 전혀 차이가 없고 단지 입출력시 \n 코드를 어떠한 방식으로 처리하는가만 다르다.

■ 텍스트 방식

파일 입출력시 \n(행바꿈 : New Line)과 \r(커서를 행의 선두로 이동 : Carriage Return)은 다음과 같이 처리된다(conio.h 함수는 예외).

        출력시 : \n ⇒ \n\r(즉 행을 바꾸고 커서를 행의 시작 위치로 이동)로 출력한다.

         입력시 : \n\r ⇒ \n으로만 읽혀진다.

이에 의해 출력시에는 \n 코드 하나만을 사용해도 행이 바뀌고(\n) 커서가 행의 시작 위치로 이동한다(\n).  즉 \n만을 출력함으로써 CR(Carriage Ruturn), LF(Line Feed : 행바꿈)를 모두 수행할 수 있다.  반대로 입력시에는 코드 \n\r은 \n 하나만으로 읽어 들인다.

■ 이진 방식

          출력시 : \n ⇒ \n 하나로 출력(즉 행만 바꾼다).
   
          입력시 : \n\r ⇒ \n\r로 읽혀진다.

즉 있는 그대로 입출력한다.

(4) fclose() : 파일을 닫는다.

원   형   int fclose(FOLE *fp);

기   능   fp가 가리키는 파일을 닫는다.   파일이 쓰기용으로 열려져 있으면 파일이 닫혀지기에 앞서 해당 파일 버퍼의 내용이 모두 파일에 출력된다.

함수값  파일이 닫혀졌으면 0, 닫혀지지 않았으면(에러가 발생했으면) -1(EOF).

프로그램 실행 종료시에는 열려져 있는 모든 파일이 자동적으로 닫혀진다.  파일에 대해 출력을 수행한 경우, 파일이 닫혀지지 않으면 파일 내용이 일부 또는 전부 손실된다.  경우에   따라서는 파일이 아무런 내용도 갖고 있지 않을 수도 있다. 따라서 파일을 사용할 때에는 반드시 fclose() 함수를 사용하여 파일을 닫아 두도록 한다.  다음에 파일을 닫지 않은 경우의 예를 표시하였다.

#include <stdio.h>

 

void main()

{

    char c;

    FILE *fp;

 

    fp = fopen("SHINDJ.TXT""w");

 

    for = ( c='A'; c<='Z'; c++)

        fputc(c, fp);

 

    printf("n Ctrl+C 키를 눌러 프로그램을 종료하십시오");

 

    getchar();

}


프로그램 실행시 메시지『Ctrl+C 키를 눌러 ...』에 대해 Ctrl+C 키를 누르면 프로그램의 실행이 강제적으로 종료되고 따라서 열려진 파일 SHINDJ.TXT가 닫혀지지 않는다.  DIR 명령의 실행 결과를 보면 파일은 생성되어 있으나 파일의 크기가 0인 것이 출력한 자료가 버퍼에 있는 상태에서 파일에 출력되지 않고 실행이 종료되었기 때문이다.

위로


입 출 력

(1) 문자, 문자열 입출력

파일에 문자, 문자열을 입출력할 때에는 fgetc(), fputc(), fgets(), fputs() 함수를 사용한다.

원   형   int fgptc(FILE *fp);

함수값   fp가 가리키는 파일의 현재의 입출력 위치에서 읽어들인 한 문자(의 애스키 코드).  읽는 도중 에러가 발생했으면 -1(EOF)


원   형   int fputc(int c, FILE *fp);

기   능   fp가 가리키는 파일에 문자 c를 출력

함수값  출력된 문자 c(애스키 코드).  에러가 발생했으면 -1(EOF)


원   형   char *fgets(char *s, int n, FILE *fp);

기   능   파일에서 n-1문자를 읽어들여 포인터 s가 가리키는 위치에 수록한다.  문자를 읽어들이는 도중 행의 끝에 도달하면 읽기가 중단된다.

함수값   성공적으로 문자열을 읽어들인 경우에는 s(읽혀진 문자열이 수록된 영역의 시작 주소), 읽어들이지 못했으면 0(NULL)


원   형   int fputs(char *s,  FILE *fp);

기   능   파일에 문자열 s를 출력한다(s가 가리키는 영역에 수록되어 있는 문자열을 출력한다.)

함수값   성공적으로 문자열을 출력한 경우에는 마지막으로 출력된 문자의 애스키 코드, 에러가 발생했으면 -1(EOF)


원   형   int feof(FILE *fp);

함수값   현재의 입출력 위치가 파일의 끝이면 0이 아닌 정수(참), 파일 끝이 아니면 0(거짓)

입출력 후 파일의 입출력 위치는 입출력된 문자수만큼 파일 뒤로 이동한다.  입출력시 에러가 발생하면 fgetc(), fputc(), fputs() 모두 -1을 되돌린다.  프로그램 중에서 이 값을 사용할 때에는 보통 -1 대신 매크로 EOF를 사용한다.  EOF는 stdio.h에 -1로 정의되어 있다.

다음은 내용이 ABCD ... XYZ인 ALPHABET.TXT 파일을 만들고 이 파일에서 1, 2, 3, ... 문자씩 읽어들여(fgets()) ALPHA.TXT 파일에 출력한다(fputs()).

#include <stdio.h>

 

void main()

{

    char c, s[128];

    int i;

    FILE *fp1, *fp2;

 

    fp1 = fopen("ALPHABET.TXT""w");

 

    for ( c='A' ;  c<='Z' ;  c++)

        fputc(c, fp1);

    fclose(fp1);

 

    fp1 = fopen("ALPHABET.TXT""r");

    fp2 = fopen("ALPHA.TXT""w");

 

    puts("ni읽힌 문자열\마지막에 출력된 문자");

 

    for ( i=1; ! feof(fp1); i++)

                  {

        printf("%d", i);

        printf("t%s", fgets(s, i, fp1));

        printf("tt%cn", fputs(s, fp2));

        fputc('n', fp2);

    }

    fcloseall();

}

fgets(s, i, fp1)은 fp1이 가리키는 파일에서 i-1 문자를 읽어들여 s에 수록하고 함수값으로 s를 되돌린다.  따라서 printf"\n%s", fgets(s, i, fp1))은 읽혀진 문자열(s)를 화면에 출력한다.

ffputs(s, fp2)는 s에 수록되어 있는 문자열을 fp2가 가리키는 파일에 출력하고 함수값으로 마지막에 출력된 문자를 되돌린다.   i=1일 때 fgets(s, i, fp1)은 0문자를 s에 읽어들이므로 즉 한 문자도 읽어들이지 않으므로 s에는 아무 문자도 수록되어 있지 않고,   따라서 fputs(s, fp2)는 fp2에 아무런 문자도 출력하지 않으므로 함수값으로는 엉뚱한 문자(위의 결과로 '[')를 되돌린다.

(2) 양식을 지정하여 입출력

양식을 지정하여 파일에 입출력할 때에는 fprintf(), fscanf() 함수를 사용한다.

원   형   int fprintf("FILE *fp, char *format, ... );

함수값   파일에 출력된 바이트수, 에러 발생시에는 ~1(EOF)


원   형   int fscanf(FILE *fp, char *format, ... );

함수값   파일에서 읽혀진 자료의 갯수, 에러 발생시에는 ~1(EOF)

파일에 입출력한다는 점을 제외하고는 구체적인 내용은 printf(), scanf() 함수와 동일하다.

위로


입출력 위치 제어

(1) 입출력 위치 이동

파일의 입출력 위치는 입출력된 문자수(바이트수)만큼 자동적으로 파일 뒤로 이동하는데, 입출력 위치를 강제적으로 다른 곳을 이동시킬 때에는 fseek() 함수를 사용한다.

원   형   int fseek(FILE *fp, long n, int where);

기   능   fp가 가리키는 파일의 입출력 위치를 where에서부터 n바이트 이동시킨다.  where은 SEEK_SET, SEEK_CUR, SEEK_END중 어느 하나이다.  이들             매크로 stdio.h 에 정의되어 있다.

함수값   실행 성공시에는 0, 에러 발생시에는 0이 아닌 정수

예   제   fseek(fp, 0, SEEK_SET);           입출력 위치를 파일 시작 위치로 이동
            fseef(fp, 5, SEEK_CUR);           현재 위치에서 5바이트 다음 위치로 이동
            fseek(fp, -3, SEEK_END);         파일 끝 위치에서 3바이트 이전 위치로 이동

SEEK_CUR, SEEK_END는 텍스트 방식으로 열려진 파일에 대해서는 정상적인 실행이 보장되지 않는다.  따라서 이를 사용하려면 파일을 이진 방식으로 열어야 한다.

(2) 입출력 위치 조사

파일의 현재의 입출력 조사할 때에는 ftell() 함수를 사용한다.

원   형   long ftell(FILE *fp);*

기   능   fp가 가리키는 파일의 현재의 입출력 위치(0부터 시작).  파일에 에러가 발생한 경우에는 -1(EOF)

다음에 fseek(), ftell() 함수의 사용예를 표시하였다.

void main()

{

    char c;

    int i;

    long wichi;

    FILE *fp;

 

    fp = fopen("ALPHABET.TXT""w+b");

 

    for (c = 'A'; c<='Z'; c++)

        fputc(c, fp);

 

    fseek(fp, 0, SEEK_SET);

 

    for (i=0; i<3; i++)

                  {

        wichi = ftell(fp);

        c = fgetc(fp);

        printf("n%c : %d", c, wichi);

    }

    putchar('\n');

 

    fseek(fp, -5, SEEK_END);

 

    for ( i=0; i<3; i++)

{

        wichi = ftell(fp);

        c = fgetc(fp);

        printf("n%c : %d", c, wichi);

    }

    putchar('n');

 

    fseek(fp, -10, SEEK_CUR);

 

    for (i=0; i<3; i++)

    {

        wichi = ftell(fp);

        c = fgetc(fp);

        printf("n%c : %d", c, wichi);

        fseek(fp, -2, SEEK_CUR);

    }

   fclose(fp);

}


프로그램 끝 부분의 fseek(fp, -2, SEEK_CUR)는 입출력 위치를 현재 위치에서부터 2문자 전 위치로 이동시킨다.  이 함수 위에 있는 c=fgetc(fp)가 실행되면 입출력 위치는『읽어들인 문자 다음 위치』로 이동한다.  따라서 fseek(fp, -2, SEEK_CUR)는 입출력 위치를『읽어들인 문자 이전 문자』로 이동시킨다.  이를 fseek(fp, -1, SEEK_CUR)로 하면 이전에 읽어들인 문자로 이동시킨다.

파일의 이곳저곳을 왔다갔다 하면서 입출력을 수행할 때에는(랜덤 입출력) fseek() 함수가 아주 중요한 역할을 한다.

위 프로그램 실행 결과에서 확인할 수 있듯이 입출력 위치는 1이 아닌 0부터 시작한다.  주의하기 바란다.

위로



블록 입출력

파일에 블록 단위로 입출력할 때에는 fread(), fwrit() 함수를 사용한다.

원   형   unsigned fwrite(void $buffer, unsigned size, unsigned n, FILE *fp);

기   능   buffer에 수록되어 있는 내용중 앞에서부터 size 바이트의 블록 n개를 fp가 가리키는 파일에 출력(앞에서부터 size × n 바이트를 출력)

함수값   실제로 출력된 블록의 갯수


원   형   unsigned fwrite(void *buffer, unsigned size, unsigned n, FILE *fp);

기   능   fp가 가리키는 파일의 현재의 입출력 위치에서 size 바이트의 블록 n개를 읽어(size × n 바이트를 읽어) buffer에 수록

함수값   실제로 입력된 블록의 갯수

다음 프로그램은 파일명을 입력받아 파일의 내용을 통째로 buffer에 읽어들여 표시한후 파일의 내용을 대문자로 바꾸어(strupr(buffer)) DAEMUNJA 파일에 출력한다.

                                         

#include <stdio.h>

#include <malloc.h>

#include <stdlib.h>

#include <string.h>

 

void PyoSi_DaeFileJSung(char *);

 

void main()

{

    char file[128];

 

    printf("파일명 .....? "); scanf("%s", file);

 

    PyoSi_DaeFileJSung( file );

}

 

void PySi_DaeFileJSung(char *file)

{

    char *buffer;

    unsigned bytesu;

    FILE *fp;

 

    fp = fopen(file, "rb");

 

    if (fp = NULL)

    {

        printf("파일이 없습니다.n");

        exit(1);

    }

 

    fseek(fp, 0, SEEK_END);

    bytesu = ftell( fp );

    buffer = (char *)malloc( bytesu );

 

    fseek(fp, 0, SEEK_SET);

    fread(buffer, bytesu, 1, fp);

    fclose(fp);

 

    buffer[bytesu] = 0;

    printf("n%sn", buffer);

 

    fp = fopen( "DAEMUNJA""wb");

    fwrite((void *)strupr(buffer), bytesu, 1, fp);

 

    fclose(fp);

}



fopen(file, "rb")를 fopen(file, "r")로 하면 파일이 텍스트 방식으로 열려지는데, 이 경우에는 프로그램 실행이 비정상적이 된다.  이는 fseek() 함수는『이진 방식으로 열려진 파일』에 대해서만 입출력 위치를 정확히 이동시키기 때문이다.

fseek(fp, 0, SEEK_END);
bytesu =ftell( fp );
buffer = (char *)malloc( bytesu );

fseek(fp, 0, SEED_END)는 입출력 위치를 파일 끝 위치로 이동시킨다.  이 결과 파일의 크기가 예를 들어 100바이트인 경우 파일의 입출력 위치는 100이 된다. bytesu = ftell(fp)는 파일의 크기인 100을 bytesu에 구하며 malloc() 함수는 buffer에 100바이트의 메모리를 할당한다.

fseek(fp, 0, SEEK_SET);
fread(buffer, bytesu, 1, fp);
fclose(fp);

buffer[bytesu] = 0;
printf("\n%s\n", buffer);

앞의 fseek(fp, 0, SEEK_END)에 의해 입출력 위치가 파일 끝으로 이동해 있는 상태이므로 파일 시작부터 읽어들이려면 fseek(fp, 0, SEEK_SET)로 입출력 위치를 파일 시작으로 이동시켜 주어야한다.  fread(buffer, bytesu, 1, fp)는 현재의 입출력 위치,즉 파일 시작 위치에서부터 bytesu × 1 바이트만큼을 읽어들여 buffer에 수록한다.  buffer[bytesu] =0은 읽혀진 블록의 제일 끝에 0을 추가함으로써 블록의 내용을 문자열의 형태로 만든다.

fp = fopen(DAEMUNJA", "wb");
fwrite((void *)strupr(buffer), bytesu, 1, fp);

fopen("DAEMUNJA", "wb")는 디스크상에 DAEMUNJA 파일을 생성하여 쓰기용으로 연다.  fwrite()는 buffer의 각 문자를 대문자로 바꾼 값인 strupr(buffer)중 처음 bytesu × 1바이트를 DAEMUNJA 파일에 출력한다.  strupr() 함수값은 char형 포이터인데 (void *)는 이를 void형 포인터로 변환한다.

posted by Kanais