24. 파일입.출력

I. 파일의 개방(Open)과 종결(Close)

  • 파일의 개방(open)

    • 파일을 개방한다는 의미는 파일과 데이터를 주고 받을 수 있는 스트림을 생성한다는 뜻
    • fopen : #include<stdio.h> FILE* fopen(const char* filename, const char* mode);이 함수 원형이다.

      • filename은  open 시킬 파일의 경로이다.
      • mode는 oper시킬 파일을 어떤 식으로 열지에 대한 것이다.

 

  • 파일 접근 모드

    • r : 파일을 읽기 위해서 개방한다. only read
    • w : 데이트를 쓰기 위해서 개방한다. only write, 지정해준 파일이 없을 경우 알아서 생성한다.
    • a : 지정해준 파일이 존재하면 데이터를 지우지 않고 그 파일의 끝에서부터 데이터를 추가한다.
    • r+ : 읽고 쓰기 위해 개방한다. 파일이 존재 안할경우 생성하고, 존재할 경우 파일을 지우기는 않고 덮어쓴다.
    • w+ : r+ 모드와 달리 파일이 존재하면 파일 자체를 지워버리고 기록한다.
    • a+ : r+ 모드와 달리 파일이 존재파면 파일의 끝에서부터 데이트를 추가한다.

 

  • 데이터 입.출력 모드

    • t : 텍스트모드
    • b : 2진 모드
    • CR : 특수문자 '\r'로 표현되며, 커서의 위치를 그 줄 매 앞으로 이동하라는 의미이다.
  1. #include <stdio.h>
  2. int main()
    {
     printf("ABCDEFG\r");
     printf("1234567 ");
     return 0;
    }
  • 위의 소스에서 보면 \r를 써서 ABCDEFG를 찍고 나서 커서를 맨 앞으로 옮기고 그다음에 1234567를 찍기 때문에 ABCDEFG가 사라진다.

    • LF : 특수문자 '\n'로 표현되며 커서의 위치를 그 다음 줄로 이동하라는 의미이다. 단, 커서의 위치까지 맨 앞으로 이동하라는 뜻은 아니다.

       23.jpg

      • 위와 같은 형태로 된다.
  1.  #include <stdio.h>
  2. int main()
    {
     printf("ABCDEFG\n");
     printf("1234567 ");
     return 0;
    }
  • 위와 같은 소스의 결과를 보면 \n에 대한 그림처럼 나오지 않고 \r\n이 합쳐진 결과값이 나온다.

    • 이유는 아래쪽에서 설명하겠다.

 

  • 텍스트 모드와 2진 모드

    • 2진 모드 : 프로그램상에서 파일로 데이터를 쓰거나 읽어 들이는 경우에 아무런 데이터의 변환도 일으키지 않는 데이터 입출력모드
    • 텍스트 모드 : 프로그램상에서 파일로 데이터를 쓰거나 읽어들이는 경우에 데이터 변환이 일어나는 입출력 모드
    • 텍스트 모드일때 C프로그램에서 \n는 \r\n으로 변형되서 인식을 한다.
    • 따라서 문자열과 같은 텍스트 기반의 데이터는 텍스트 모드로
    • 데이터의 변환이 발생하면 안되는 경우(영상 데이터 입출력 같은)에는 2진 모드로 데이터를 입출력해야한다.

 

  • 파일 개방 모드의 완성

    • 여기서 말하고 싶은건 위에서 파일접근모드와 데이터 입.출력모드의 구성을 조합해서 쓸수 있다는 내용이다.

 

  • FILE 구조체의 포인터(파일 포인터)

    • 지정한 파일과의 데이터 입.출력을 위해 스트림을 생성하는 함수이다.
    • 리턴 값은 무엇인가?

      • FILE이라는 구조체 변수의 포인터이다.
      • FILE 구조체 변수는 개방한 파일에 대한 여러가지 정보를 지니는 변수이다.
    • 무슨 목적으로 사용하게 되는가? 

      •  데이터를 입.출력할때 : FILE 구조체 변수를 참조하면 데이터를 입출력할 파일이 무엇인지 알 수 있다.
      • 위치 정보를 참조 할 때 : FILE 구조체 변수는 파일 내의 위치 정보를 지니고 있다. 이를 참조하면 해당 파일의 어느 위치까지 데이터를 입력 혹은 출력했는지 알 수 있다.
      • 파일의 끝을 확인 할 때 : FILE 구조체 변수를 참조하면 파일의 끝까지 데이터를 읽어 들였는지에 대한 정보를 알 수 있다.

 

  • 파일의 종결(close)

    • fclose : #include<stdio.h> int fclose(FILE* stream)이 함수원형이며 해당 스트림을 소멸 하는게 역할이다.
  1.  #include <stdio.h>
  2. int main()
    {
     int state;
     FILE* file = fopen("Test.txt","wt");
     if(file==NULL)
     {
      printf("file open error\n");
      return 1;
     }
     state = fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
     return 0;
    }
  •  위에서 오픈모드를 wt로 하였기 때문에 Test.txt라는 이름의 파일이 존재하지 않으면 현재 디렉토리에 파일이 생성될 것이다.

 

II. 파일 입.출력 함수

 

기능 / 스트림 키보드/모니터 선택(키보드/모니터,파일)
 문자 출력 int putchar(int c) int fputc(int c,FILE* stream)
 문자 입력 int getchar(void) int fgetc(FILE* stream)
 문자열 출력 int puts(cpmst char* s) int fputs(const char*s, FILE* stream)
 문자열 입력 char* gets(char* s) char* fgets(char* s,int n,FILE* stream)
 형식 지정 출력 int printf(const* format,...) int fprintf(FILE* stream,const char* format,...)
 형식 지정 입력  int scanf(const char* format,...) int fscanf(FILE* stream, const char* format,...)
     
  • fputs 함수를 이용한 파일 출력
  1. #include <stdio.h>
  2. int main()
    {
     int state;
  3.  FILE* file = fopen("Test.txt","wt");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     puts("Dont's Worry!");
     fputs("Dont's Worry!\n",stdout);
     fputs("Dont's Worry!\n",file);
  4.  state = fclose(file);
     if (state!=0)
     {
      printf("file open error!\n");
      return 1;
     }
     return 0;
    }
  • puts로 문자열을 모니터에 찍고, fputs로 스트림이 stdout이니까 모니터에 출력하고 그다음 fputs에서 스트림이 file이므로 Test.txt  파일에 저장한다.

 

  • fgets 함수를 이용한 파일 입력
  1. #include <stdio.h>
  2. int main()
    {
     int state;
     char buf[30];
  3.  FILE* file = fopen("Test.txt","rt");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     fputs("데이터 입력:",stdout);
     fgets(buf, sizeof(buf),stdin);
     puts(buf);
  4.  fgets(buf,sizeof(buf),file);
     puts(buf);
  5.  state = fclose(file);
     if (state!=0)
     {
      printf("file open error!\n");
      return 1;
     }
     return 0;
    }
  • fgets로 먼저 키보드에서 받아드린 값을 puts로 모니터상에 출력을 하고 두번째 fgets는 file로 부터 문자열을 읽어와서 puts로 출력을 한다.(Test.txt 파일안에 글이 있다면 화면에 찍힌다.)

    • 위 소스에서 문제점은 만약 배열의 크기를 넘어 가면 어떻게 할것인가 이다.
    • 따라서 파일의 끝에 도달했을음 확인할 방법을 찾으면 된다.

 

  • fprintf와 fscanf 함수를 이용한 파일 입.출력
  1. #include <stdio.h>
  2. int main()
    {
     int state;
     int i,j;
     int a=0,b=0,c=0;
     char c1=0,c2=0;
  3.  FILE* file = fopen("Test.txt","wt");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
  4.  for(i = 2;i<10;i++)
      for(j=1;j<10;j++)
       fprintf(file,"%d * %d = %d\n",i,j,i*j);
  5.  state = fclose(file);
     if (state !=0)
     {
      printf("file close error!\n");
      return 1;
     }
     file = fopen("Test.txt","rt");
     if (file == NULL)
     {
      printf("file open error!\n");
      return 1;
     }
  6.  for(i=2;i<10;i++)
      for (j=1;j<10;j++)
      {
       fscanf(file,"%d %c %d %c %d",&a,&c1,&b,&c2,&c);
       printf("%d %c %d %c %d\n",a,c1,b,c2,c);
      }
  7.   state = fclose(file);
      if(state!=0)
      {
       printf("file close error!\n");
       return 1;
      }
      return 0;
    }
  • 파일 입.출력 함수와 FILE 구조체 변수

    • 파일 위치 지시자 : 파일을 어디까지 읽었는지, 어디까지 썼는지 그 위치를 기억하고 있다는 뜻 이러한 정보를 기억하고 있는 변수

 

III. 파일의 끝을 확인합시다.

  • 리턴 값을 참조하는 방법

 

함수 파일의 끝에서 리턴 되는 값
 fgetc  EOF(-1)
 fgets  NULL 포인터(0)
 fscanf  EOF(-1)
  1. #include<stdio.h>
  2. int main()
    {
     int state;
     char* pState;
     char str[20];
  3.  FILE* file = fopen("Test.txt","rt");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
  4.  while (1)
     {
      pState = fgets(str,sizeof(str),file);
      if (pState == NULL)
       break;
      fputs(str,stdout);
     }
  5.  state = fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
     return 0;
    }
  • while 문에서 파일의 끝이 나올때 까지 반복하면서 데이터를 읽어 들인다.(참고로 이전에 만들어진 구구단 test.txt를 가지고 하는 것이다.)

 

  1.  #include <stdio.h>
  2. int main()
    {
     int state;
     char ch;
  3.  FILE* file = fopen("Test.txt","wb");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     fputc('1',file);
     fputc((char)255,file);
     fputc('2',file);
  4.  state=fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
  5.  file = fopen("Test.txt","rb");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     while (1)
     {
      ch = fgetc(file);
      if (ch == -1)
       break;
      printf("data : %c\n",ch);
     }
     state = fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
  6.  return 0;
    }
  • 결과값을 찍어 보자

    • 위에서 1, (char)255, 2 를 저장하였음에도 불구하고 1만 출력되는 것을 볼 수 있다.
    • (char)255는 10진수로 -1이다. 그런데 while문에서 -1이 file 안에 있다면 반복문을 빠져 나오는 것인데 (char)255를 -1으로 인식하여 종료가 되는 것이다.

 

  1. #include <stdio.h>
  2. int main()
    {
     int state;
     int ch;
  3.  FILE* file = fopen("Test.txt","wb");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     fputc('1',file);
     fputc((char)255,file);
     fputc('2',file);
  4.  state=fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
  5.  file = fopen("Test.txt","rb");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     while (1)
     {
      ch = fgetc(file);
      if (ch == -1)
       break;
      printf("data : %c\n",ch);
     }
     state = fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
  6.  return 0;
    }
  •  위 소스는 이전 소스에서 char ch를 int ch로 바뀐 점이다.

    • 여기에 대한 설명은 아직 제대로 이해를 못해서 책을 봐주세요 ;;;

 

  • feof 함수를 사용하는 방법

    • feof : #include<stdio.h> int feof(FILE* stream)이 함수 원형이며 호출시 전달되는 파일 포인터가 가리키는 파일이 끝에 도달한 경우 0이 아닌 값을 리턴한다.

 

  1. #include <stdio.h>
  2. int main()
    {
     int state;
     char ch;
  3.  FILE* file = fopen("Test.txt","wb");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     fputc('1',file);
     fputc((char)255,file);
     fputc('2',file);
  4.  state=fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
  5.  file = fopen("Test.txt","rb");
     if (file==NULL)
     {
      printf("file open error!\n");
      return 1;
     }
     while (1)
     {
      ch = fgetc(file);
      if (feof(file)!=0)
       break;
      printf("data : %c\n",ch);
     }
  6.  state = fclose(file);
     if (state!=0)
     {
      printf("file close error!\n");
      return 1;
     }
  7.  return 0;
    }
  • 책에서 나온 실행 결과는 잘못된 것이고 p.558에 있는 실행결과처럼 나와야 한다.

    • 이전 소스에서는 while문 안에 if(ch == -1) 일때 반복문을 빠져 나오게 하였지만 좋지 못한 결과가 나오기도 했다.

      • 그러나 feof를 써서 0이 아닌 값 즉 파일의 끝에 도달하면 0이 아닌 값을 리턴 할때 반복문을 빠져 나오게 한다.

 

IV. Random Access 파일 입.출력

  • fseek : #include<stdio.h> int fseek(FILE* stream, long offset, int wherefrom)이 함수원형

    • 파일 위치 지시자를 원하는 위치에 놓을 수 있다.  stream이 가리키는 파일의 파일 위치 지시자를 시작 위치 wherefrom에서부터 offset 만큼 이동한다.
만약에 wherefrom이 파일 위치 지시자를 offset 만큼 이동하기 전에
 SEEK_SET(0)이라면  파일의 맨 앞으로 이동한다.
 SEEK_CUR(1)이라면  이동하지 않는다.
 SEEK_END(2)이라면  파일의 끝으로 이동한다.
  1.  #include <stdio.h>
  2. int main()
    {
     char buf[10];
  3.  FILE* file = fopen("Test.txt","wt");
     fputs("1234abcd56789",file);
     fclose(file);
  4.  file = fopen("Test.txt","rt");
     fgets(buf,7,file);
     printf("%s\n",buf);
  5.  fseek(file, 2, SEEK_CUR);
     printf("%c\n",fgetc(file));
     fseek(file,-2,SEEK_CUR);
     printf("%c\n",fgetc(file));
     fseek(file,2,SEEK_SET);
     printf("%c\n",fgetc(file));
     fseek(file,-2,SEEK_END);
     printf("%c\n",fgetc(file));
     fclose(file);
     return 0;
    }

이 글은 스프링노트에서 작성되었습니다.

Posted by kid1412
,