C Programming [Stream and File IO]

 Published On

스트림과 파일 입출력

  1. 스트림 : 모든 입력과 출력을 바이트들의 흐름으로 생각하는 것

  2. 스트림의 장점 - 장치 독립성(입출력 장치에 상관없이 프로그램을 작성)

  3. 스트림의 특징 - 버퍼를 사용(버퍼에 데이터 저장, 전송)

  4. 표준 입출력 스트림
    1) stdin 표준 입력 스트림 scanf()
    2) stdout 표준 출력 스트림 printf()
    3) stderr 표준 오류 스트림 fprintf(stderr)

  5. 입출력 함수
    1) 형식이 없는 입출력(문자 형태)

    표준      :    일반  
    getchar() :    fgetc(File *f)  
    putchar() :    fputc(File *f)  
    gets()    :    fgets(File *f)  
    puts()    :    fputs(File *f)  
    

    2) 형식이 있는 입출력(정수, 실수)

    표준     :    일반  
    printf() :    fprintf(File *f)  
    scanf()  :    fscanf(File *f)  
    
  6. C에서의 모든 입력과 출력은 스트림 형식으로 처리된다.

  7. 스트림은 모든 입력과 출력을 바이트들의 흐름으로 간주한다.

  8. 스트림의 최대 장점은 장치 독립성이다.

  9. 입력을 위한 표준적인 스트림은 stdin이고 기본적으로 키보드 장치와 연결된다.

  10. 출력을 위한 표준적인 스트림은 stdout이고 기본적으로 콘솔화면 장치와 연결된다.

  11. printf(형식 제어 문자열)
    • printf(%[플래그] [필드폭] [정밀도] 형식)
    • 플래그(flag) : 하나의 문자로서 출력의 정렬과 부호 출력, 공백 출력, 8진수와 16진수 접두사 출력 등을 지시한다.
    • ‘-’ : 왼쪽 정렬, 기본 : 오른쪽 정렬
    • ‘+’ : 결과값을 출력할 때 항상 +와 -의 부호를 붙임
    • ‘0’ : 출력값 앞에 공백 문자 대신에 0으로 채움
    • ‘ ’ : 출력값 앞에 양수나 영인 경우 부호 대신 공백을 출력
    • ‘#’ : 8진수 출력일 때는 출력값 앞에 0, 16진수는 출력값 앞에 0x


  12. printf()에서 변수나 수식의 값을 출력하는 형식을 지정하는 문자열은 형식제어 문자열이다.

  13. printf()에서 정렬을 구체적으로 지시하지 않으면 기본적으로 오른쪽 정렬된다.

  14. 형식 지정자 %d와 %i은 부호 있는 정수를 10진수 형태로 출력하는데 사용된다.

  15. 부호 없는 8진수, 10진수, 16진수 정수를 출력하는 사용되는 형식 지정자는 %o, %d, %x이다.

  16. 실수를 지수 표기법으로 출력하는데 사용되는 형식 지정자는 %e이다.

  17. 정수를 필드폭 6으로 출력하려면 %6d로 하여야 한다.

  18. 실수를 필드폭 10이고 소수점 이하 자릿수를 6자리로 출력하려면 %10.6f로 하여야 한다.

  19. 출력값을 왼쪽 정렬시키는 플래그는 -이다.

  20. 실수 출력의 경우, 정밀도를 지정하지 않으면 소수점 이하 자릿수는 기본적으로 6개가 된다.

  21. scanf()를 이용한 입력
    • 문자들을 모아서 정수나 실수로 변환한다.
    • 필드폭이 5가 지정되면 2개의 숫자와 3개의 숫자로 읽어질 수도 있다.
      ex) 6개의 숫자로 이루어진 정수 입력 -> scanf(“%3d%3d”, &a, &b);

    • %c : char형으로 입력받는다.
    • %s : 공백 문자가 아닌 문자부터 공백 문자가 나올 때까지를 문자열로 변환하여 입력받는다.
    • %[abc] : 대괄호 안에 있는 문자 a,b,c로만 이루어진 문자열을 읽어들인다(첫 번째 문자가 문자 집합에 없으면 문자 배열에 아무것도 저장 안됨)
    • %[^abc] : 대괄호 안에 있는 문자 a,b,c만을 제외하고 다른 문자들로 이루어진 문자열을 읽어 들인다.
    • %[0-9] : 0에서 9까지의 범위에 있는 문자들로 이루어진 문자열을 읽어들인다.
      -fflush(stdin) : 버퍼에 남아있는 데이터를 비움


  22. scanf()에서 double 값을 입력받을 때 사용하는 형식 지정자는 %lf이다.

  23. 여러 개의 입력을 받는 경우, scanf()는 공백문자를 이용하여 각각의 입력을 분리한다.

  24. 파일의 기초
    • 변수, 배열, 구조체 등은 모두 메모리로 만들어지고 이것들은 전원이 꺼지면 사라진다. -> 휘발성
    • 하드 디스크에 파일 형태로 저장하면 전원이 꺼지더라도 데이터가 보존된다. -> 비휘발성
    • 파일도 일련의 연속된 바이트이다.
    • 모든 파일은 입출력 동작이 발생하는 현재 위치를 나타내는 파일 포인터를 가지고 있다.
    • 텍스트 파일에서는 문자열의 끝을 나타내는데 NULL 문자를 사용하지 않는다. 대신 줄의 끝을 표현하기 위해 ‘\n’을 사용한다.

  25. 텍스트 파일
    • 소스파일이나 메모장 파일
    • 아스키 코드를 이용한 문자들이 포함
    • 모니터, 키보드, 프린터 등이 문자 데이터만을 처리
    • 연속적인 줄들로 구성
    • 각 줄은 줄의 끝을 알리는 문자로 종료
    • 윈도우즈는 캐리지 리턴과 줄바꿈 문자의 조합(CR-LF)으로 줄의 끝
    • 유닉스는 줄바꿈 문자(LF)로 줄의 끝
    • 매킨토시는 캐리지 리턴(CR)로 줄의 끝

  26. 이진 파일
    • 사람은 못 읽고 컴퓨터는 읽는 파일
    • 텍스트 파일과 달리 줄들로 분리되어 있지 않음 -> 줄의 끝 필요(x)
    • 이진수 형태로 저장
    • NULL, CR, LF 모두 단순한 데이터 취급
    • 실행 파일, 사운드 파일, 이미지 파일

  27. 파일 열기 -> 읽기와 쓰기 -> 파일 닫기

  28. 파일 열기
    • File *fopen(const char *name(파일 이름), const char *mode(파일 모드))
    • 만약 실패하면 NULL포인터 반환
    • 파일 모드

      “r" : 읽기 모드로 파일을 연다. 파일이 없으면 오류가 발생한다.
      "w" : 쓰기 모드로 파일을 생성한다. 파일이 이미 존재하면 기존 내용은 지워진다.
      “a" : 추가 모드로 파일을 연다. 파일이 이미 존재하면 데이터가 파일의 끝에 추가된다. 파일이 없으면 새로운 파일을 만든다.
      “r+" : 읽기 모드로 파일을 연다. 쓰기 모드로 전환할 수 있다. 파일이 반드시 존재해야 한다.
      “w+" : 쓰기 모드로 새로운 파일을 생성한다. 읽기 모드로 전환할 수 있다. 파일이 이미 존재하면 기존 내용은 지워진다.
      “a+" : 추가 모드로 파일을 연다. 읽기 모드로 전환할 수 있다. 데이터를 추가하면 EOF 마커를 추가된 데이터의 뒤로 이동한다. 파일이 없으면 새로운 파일을 만든다.
      “t" : 텍스트 파일 모드로 파일을 연다.
      "b" : 이진 파일 모드로 파일을 연다.
      "a", "a+" : 추가 모드
      "r+", "w+", "a+" : 수정 모드(전환하려면 fflush(), fsetpos(), fseek(), rewind() 중의 하나를 호출해야 한다)
      
  29. 파일 닫기
    • fclose() : 성공하면 0, 실패하면 -1 반환
  30. 파일 삭제
    • remove() : 성공하면 0, 실패하면 -1 반환
  31. 기타 함수들
    • feof() : 파일의 끝에 도달되면 true를 반환한다
    • rename(const char *oldname, const char *newname) : 파일 이름 변경
    • FILE *tmpfile() : 임시 파일 생성하여 반환
    • ferror() : 스트림의 오류 상태를 반환한다. 오류가 발생하면 true를 반환

  32. 파일은 일련의 연속된 바이트라고 생각할 수 있다.

  33. 파일에는 사람이 읽을 수 있는 텍스트가 들어 있는 텍스트 파일과 사람이 읽을 수 없으나 컴퓨터는 읽을 수 있는 이진 파일이 있다.

  34. 파일을 여는 라이브러리 함수는 fopen() 이다.

  35. fopen()은 FILE을 가리키는 포인터를 반환한다.

  36. 텍스트 파일 읽기와 쓰기 1) 문자 단위 입출력

    입력(파일에서 문자를 가져옴) : fgetc(FILE *fp)  
    출력(파일에 문자를 작성) : fputc(int c, FILE *fp)  
    

    2) 문자열 단위 입출력

    입력 : fgets(char *s(문자열 저장), int n(최대 개수), FILE *fp)  
    출력 : fputs(char *s, FILE *fp)  
    

    3) 형식화된 입출력

    입력 : fprintf(FILE *fp, const char *format)  
    출력 : fscanf(FILE *fp, const char *format)   
    
  37. fgetc()의 반환형은 int이다.

  38. 텍스트 파일에서 하나의 줄을 읽어서 반환하는 함수는 fgets()이다.

  39. 텍스트 파일에 실수나 정수를 문자열로 변경하여 저장할 때 사용하는 함수는 fprintf()이다.

  40. 텍스트 파일에서 실수나 정수를 읽는 함수는 fscanf()이다.

    #include <stdio.h>
    #include <stdlib.h>
    int main(void) {
        FILE *fp;
        char fname[100];
        int number, count = 0;
        char name[20];
        float score, total = 0.0;
        
        printf("성적 파일의 이름을 입력하시오: ");
        scanf("%s", fname);
        
        // 성적 파일을 쓰기 모드로 연다
        if((fp = fopen(fname, "w")) == NULL) {
            fprintf(stderr, "성적 파일 %s을 열 수 없습니다.\n", fname);
            exit(1);
        }
        
        // 사용자로부터 학번, 이름, 성적을 입력받아서 파일에 저장한다.
        while(1) {
            printf("학번, 이름, 성적을 입력하세요:(음수이면 종료)");
            scanf("%d", &number);
            if(number < 0) break;
            scanf("%s %f", name, &score);
                    // 데이터는 모두 문자열로 변환
            fprintf(fp, "%d %s %f\n", number, name, score); 
        }
        fclose(fp);
        
        // 성적 파일을 읽기 모드로 연다.
        if((fp = fopen(fname, "r")) == NULL) {
            fprintf(stderr, "성적 파일 %s을 열 수 없습니다.\n", fname);
            exit(1);
        }
        
        // 파일에서 성적을 읽어서 평균을 구한다.
        while(!feof(fp)) {
            fscanf(fp, "%d %s %f", &number, name, &score);
            total += score;
            count++;
        }
        
        printf("평균 = %f\n", total / count);
        fclose(fp);
        
        return 0;
    }
    
  41. 이진 파일 읽기와 쓰기
    • 텍스트 파일과의 차이점
      1) 텍스트 파일에서는 모든 정보가 문자열로 변환되어 저장
      ex)

      123456 -> '1' '2' '3' '4' '5' '6'으로 변환되어 출력(fprintf)  
      fscanf() -> 문자를 읽어서 숫자로 변환
      

      2) 이진 파일은 데이터가 직접 저장(이진수 형태로)

      3) 이진 파일의 장점

      효율성 -> 변환 과정 없으므로 시간과 공간 절약  
      대량의 데이터를 한번에 기록할 때 편리함  
      

      4) 이진 파일의 단점

      인간이 파일의 내용을 확인하기 어려움  
      이식성이 떨어짐  
      
    • 이진 파일 쓰기
      • 파일 모드에서 “b”를 붙여줌
      • 이진 파일 출력은 메모리 블록에 있는 데이터를 디스크 파일로 직접 저장
      • fwrite(buffer(메모리 블록 주소), sizeof(int)(항목의 크기), SIZE(항목의 개수), fp)
      • 항목의 크기는 바이트 단위
    • 이진 파일 읽기
      • fread(buffer(메모리 블록 주소), sizeof(int)(항목의 크기), SIZE(항목의 개수), fp)
  42. 버퍼링
    • 버퍼는 파일로부터 읽고 쓰는 데이터의 임시 저장 장소로 이용되는 메모리의 블록
    • 버퍼를 두는 이유는 디스크에서 물리적으로 데이터를 읽을 때는 상당한 시간이 걸리기 때문에 한 번 읽을 때 많이 읽어두고 나중에 다음 데이터가 필요하면 바로 버퍼에서 갖다 주는 것이다.
    • fflush(fp)
    • 버퍼가 필요 없는 경우 -> setbuf(fp, NULL)
    • 데이터베이스
      • 데이터를 모아 놓은 것으로 손쉽게 검색 가능한 저장 기법
      • 저장 단위는 레코드

  43. 문자 데이터가 아니고 이진 데이터가 저장되어 있는 파일을 이진 파일

  44. 이진 파일을 생성할 때 사용하는 함수는 fopen()이다.

  45. 읽기 전용 이진 파일을 생성할 때 사용하는 파일 모드는 “rb”이다.

  46. 임의 접근
    1) 순차 접근

    모든 데이터를 파일의 처음부터 순차적으로 읽거나 기록  
    앞부분을 읽지 않고 중간이나 마지막으로 못감  
    

    2) 임의 접근

    파일의 어느 위치에서든지 읽기와 쓰기 가능  
    
  47. 임의 접근의 원리
    • 파일 포인터
      • 읽기와 쓰기 동작이 현재 어떤 위치에서 이루어지는 지 나타내는 것
      • 새 파일이면 파일 포인터는 0의 값(파일의 시작 부분)
      • 기존 파일에서 추가 모드에서는 파일의 끝
      • 기존 파일에서 다른 모드는 파일의 시작 부분
      • 위치 표시자를 조작하는 함수는 fseek()

      1) fseek(FILE *fp, long offset(거리), int origin(기준 위치))

      offset은 기준 위치로부터 위치 표시자가 이동하는 거리  
      offset이 양수이면 앞으로, 음수이면 뒤로 간다  
      origin  
                            
      SEEK_SET(0, 파일의 시작)
      SEEK_CUR(1, 현재 위치)
      SEEK_END(2, 파일의 끝)
      
      - 성공하면 0을, 실패하면 0이 아닌 값을 반환
             
      fseek(fp, 50L, SEEK_CUR) // 현재 위치에서 50바이트 이동
      fseek(fp, -20L, SEEK_END) // 파일의 끝에서 20바이트 앞으로 이동
      

      2) rewind(FILE *fp)

      위치 표시자가 0으로 설정  
      파일을 읽은 다음, 다시 읽고자 할 때 사용  
      

      3) ftell(FILE *fp)

      현재의 위치 표시자 값을 long형으로 반환  
      

      4) feof(FILE *fp)

       파일의 끝  
      
  48. 파일의 처음부터 순차적으로 읽거나 쓰는 방법을 순차접근이라고 한다.

  49. 파일의 어느 위치에서나 읽고 쓰기가 가능한 방법을 임의접근이라 한다.

  50. 파일에서 읽기나 쓰기가 수행되면 파일의 현재 위치를 표시하는 파일 위치 표시자가 갱신된다.

  51. 파일의 위치 표시자를 알아내는 함수는 ftell()이다.

    #include <stdio.h>
    #include <stdlib.h>
        
    #define SIZE 1000
    void init_table(int table[], int size);
        
    int main(void) {
        int table[SIZE];
        int n, data;
        long pos;
        FILE *fp = NULL;
        
        init_table(table, SIZE);
        
        // 이진 파일을 쓰기 모드로 연다.
        if((fp = fopen("sample.dat", "wb")) == NULL) {
            fprintf(stderr, "출력을 위한 파일을 열 수 없습니다.\n");
            exit(1);
        }
        
        // table 배열에 SIZE 개수만큼 4바이트씩 저장
        fwrite(table, sizeof(int), SIZE, fp);
        fclose(fp);
        
        // 이진 파일을 읽기 모드로 연다.
        if((fp = fopen("sample.dat", "rb")) == NULL) {
            fprintf(stderr, "입력을 위한 파일을 열 수 없습니다.\n");
            exit(1);
        }
        
        //사용자가 선택한 위치의 정수를 파일로부터 읽는다.
        while(1) {
            printf("파일에서의 위치를 입력하시오(0에서 %d, 종료 -1): ", SIZE - 1);
            scanf("%d", &n);
            if(n == -1) break;
            pos = (long)n * sizeof(int);
            fseek(fp, pos, SEEK_SET);
            fread(&data, sizeof(int), 1, fp);
            printf("%d 위치의 값은 %d입니다.\n", n, data);
        }
        fclose(fp);
        
        return 0;
    }
        
    // 배열을 인덱스의 제곱으로 채운다.
    void init_table(int table[], int size) {
        int i;
        
        for(i = 0; i < size; i++)
            table[i] = i * i;
    }
    
  52. 파일은 연속된 바이트의 모임이라고 생각할 수 있다.

  53. 스트림은 파일 구조체를 통하여 접근된다.

  54. 프로그램이 실행될 때 자동으로 만들어지는 3개의 스트림의 이름은 stdin, stdout, stderr이다.

  55. 파일에는 사람이 읽을 수 있는 텍스트가 들어 있는 텍스트파일과 사람은 읽을 수 없으나 컴퓨터는 읽을 수 있는 이진 파일이 있다.

  56. \n 문자는 텍스트 파일의 끝을 나타내는 특수 문자이다.

  57. 읽고 쓸 수 있는 이진 파일을 생성할 때 사용하는 파일 모드는 “r+b”이다.

  58. fgetc()의 반환형은 int형이다.

  59. 파일을 삭제하는 라이브러리 함수는 remove()이다.

  60. 파일의 어느 위치에서나 읽고 쓰기가 가능한 방법을 임의접근이라 한다.

  61. 파일의 위치 표시자를 알아내는 함수는 ftell()이다.


Tags: Language

Comments:

comments powered by Disqus

© 2021 - MH.Ji. All rights reserved
Built using Jekyll