08 파일 처리 함수

1절  파일 입출력

l  데이터를 미리 저장한 파일로 입력 받고 결과를 파일로 저장

l  <stdio.h>이 파일 입출력 함수 제공

1.     파일

n  파일 : 디스크나 자기 테이프 등과 같이 보조기억장치에 파일명으로 저장된 물리적 데이터 집합체

n  프로그램 파일 / 데이터 파일로 나뉨

1)    프로그램과 데이터

u  프로그램 : 특정 문제를 해결하기 위해 CPU가 실행할 명령을 모아둔 파일

u  데이터 : 프로그램 파일이 실행되면서 처리할 데이터 or 프로그램 실행 동안 처리한 결과 모아둔 파일

 

2)    파일에 저장된 데이터 형식에 따른 분류

(1)   텍스트 파일 : 파일 내용이 사람이 알고 있는 문자로 표시

사용자가 키보드로 직접 입력해서 만든 프로그램 소스파일/ 메모장에서 작성한 파일

(2)   이진 파일 : 컴퓨터의 특정 프로그램에 의해서만 읽을 수 있는 파일 (exe 파일, 음악/이미지 파일)

 

3)    파일은 접근 방식에 따른 분류

(1)   순차(sequential) 파일

o  데이터를 처음부터 순차적으로 읽거나 씀

o  이미 읽은 데이터를 다시 읽으려면 파일을 닫은 다음 다시 열어야 됨

o  파일의 맨 처음부터 읽어서 원하는 위치까지 이동하여 데이터를 읽어야 함

 

(2)   랜덤(random) 파일

o  파일의 어느 위치든 곧바로 이동하여 읽고 쓰기 가능

o  어떤 파일이든 순처적으로 접근할 수도 있고 임의적으로 접근할 수 도 있음

 

2.     파일 처리 과정

n  파일 포인터 선언 -> 파일 열기 -> 파일 읽기 -> 파일 닫기

1)    파일 포인터 선언

u  FILE 구조체형 포인터 필요 -> ‘파일 포인터라고 함

u  FILE : 헤더파일  stdio.h에 정의된 구조체 자료형. 파일 읽/쓰에 필요한 정보 저장하는 구조체

u  작업 대상인 파일의 정보를 전달하는 인수로 사용

u  파일 포인터가 할당되어 있는 파일에 대해서만 읽/쓰 가능

u  FILE *파일 포인터 변수명

FILE *fp;

 

2)    파일 열기 : fopen( )함수

u  파일을 open하는 작업 -> FILE 구조체를 파일 포인터와 연결

u  운영체제에게 파일 사용하겠다고 요청하는 것

u  파일 포인터 변수명 = fopen(“파일명”, ”모드”);

o  fopen 함수 : “파일명의 파일을 모드에 맞게 open한 후 파일 정보가 든 FILE구조체의 시작주소 반환

o  fopen함수가 반환한 FILE구조체 시작주소를 파일 포인터에 연결해 포인터가 참조하게 함

o  파일 열기 실패 -> NULL 반환

o  모드 : 파일 읽기 (r), 쓰기 (w) 등 지정하고 참조모드 형태모드 조합 !

 

(1)   파일 참조 모드



(2)   파일 형태 모드

 

o  파일명만 명시하면 현재 작업중인 프로젝트 폴더 안에서 파일 찾음

o  절대 경로로 명시하면 절대경로에서 파일 찾음

o  FILE *fp = fopen(:data.txt”, “w”);

                     

(3)   NULL문자 반환

o  파일 열기 실패하면 NULL문자 반환 -> 파일 관련 어떠한 작업도 더 이상 처리 안됨

o  보통 프로그램 강제로 종료하도록 exit(1); 을 함

o  FILE *fp = fopen(“data.txt”, “r”);

if(fp==NULL)

      exit(1);

 

3)    파일 입출력 함수


 

4)    파일 닫기 : fclose( )함수

u  파일 읽/쓰기 끝나면 프로그램 종료 전 반드시 열린 파일 닫아야 함

u  fclose(파일 포인터 변수명);

o  파일 포인터명과 연결된 파일이 닫히고 파일 포인터와의 연결이 해제됨

o  연결 해제된 파일 포인터는 다음 파일 다시 연결해 사용 가능

o  파일 닫기 성공하면 0 반환 / 실패하면 -1 반환 (EOF상수 : END OF FILE)

 

3.     형식을 지정한 파일 입출력

n  형식에 맞추어 읽고 쓰는 fsanf() / fprintf()! 일반 파일 뿐 아니라 장치 파일까지 입출력 할 수 있음

n  기존 파일 내용 프로그램서 읽으려면 파일에 저장된 데이터 형식 순서 알고 그에 맞게 읽어야 함

 

1)    형식을 지정한 파일 출력 : fprintf( )함수

u  fprintf(파일 포인터 변수, “변환명세 포함한 형식 문자열”, 변수명);

o  변수에 저장된 값을 형식문자열에 맞게 변환하여 파일포인터 연결된 파일에 기록

o  변수 대신 상수, 수식 가능

u  파일 포인터 변수명을 stdout으로 지정하면 모니터로 출력됨

int age = 2;

fprintf(fp, “나이 : %d”. age);

fprintf(stdout, “나이 : %d”. age);

 


u  변환 명세 형식 문자열에 빈칸이나 엔터키를 입력하여 데이터 간 구분 필요

 

2)    형식을 지정한 파일 입력 : fscanf( )함수

u  fscanf(파일 포인터 변수, “변환 명세”, &변수명)

파일 포인터에 연결된 파일에서 변환명세에 맞게 데이터를 한 개 읽어 변수명에 저장

파일 포인터 변수명을 stdin으로 지정하면 키보드에서 입력 받음

읽기에 실패하거나 파일의 끝에 도달하면 EOF 반환(성공 0 /실패 -1)

u  변환 명세 끝에 빈칸 / \n X, 일반 문자를 변환명세에 포함 X

u  FILE *fp=fopen(“read.txt”);

fscanf(fp, “%d”, &age);      --->      이러면 안됨       fscanf(fp, “ : %5d ”, &height);

                                                         변환명세에 공백, 일반 문자 X 필드폭 사용 비추

 

3)    파일 추가

u  파일 참조에 추가모드로 파일을 열어 파일의 끝에 자료 추가

u  실행결과와 같은 파일에 새 실행결과를 저장하고 싶을 때 사용

u  open할 파일 없으면 지정한 파일 이름으로 파일 새로 생성

u  fp = fopen(“text.txt”, “a”);

 

4)    파일의 끝 확인

(1)   feof( ) 함수 활용하기

o  책갈피 역할!

o  읽기/쓰기 시작할 위치를 가리키는 파일 위치 지시자(FILE 구조체의 포인터 멤버)

-      파일 위치 지시자 file position indicator -> FPI로 써야지 귀찮아

o  파일 입출력 함수 호출 시 인수로 지정한 파일 포인터가 가리키는 file구조체의 FPI가 가리키는 곳부터 읽기/쓰기 진행

-      파일 닫으면 파일 마지막 데이터 다음에 시스템에 의해 파일 끝 표시하는 특별한 문자 자동으로 저장됨(시스템만 인식 가능 ^Z(ctrl+Z)로 표현)

-      FPI가 이 특별 문자 가리킬 때 읽기 시도 -> 더 이상 읽을 데이터 없으므로 FPI는 파일의 처음 위치로 수정됨

-      FILE 구조체의 특정 플래그가 파일 끝 지났음을 표시 (1로 세팅됨)

-      플래그가 1로 세팅된 경우면 파일에서 더 읽을 자료가 없음을 의미 -> 읽기를 그만둠

 

o  feof(파일 포인터 변수명)

-      파일 포인터 변수명이 가리키는 FILE구조체에서 파일 끝 지났음을 알려주는 플래그를 참조하여 반환 값을 반환

 

o  파일 끝(문자)를 지나갔을 때 0이 아닌 값( = 1) 반환 (도달했을 때가 아님)

-      프로그램 실행을 통해 만들어지는 파일이 상황에 따라 빈 파일 만들어 지기도 함

-      데이터 전혀 없는 빈 파일 끝에는 끝 나타내는 특수문자만 포함

-      빈 파일 열고 feof( )호출하면 0 나오는데, FPI 맨 끝을 가리키기만 함

-> 끝 문자를 지나가지 않았기 때문

 

o  feof( ) 함수 사용의 잘못된 예

1

2

3

4

5

while (!feof(fp))

{

  fscanf(fp, “%d”, &age);

printf(“%2d \n, age);

}

라고 했을 때

      fp 참조 파일에 아무 데이터 없을 때

- 1 ~ 5 : FPI는 특수문자 가리키므로 !feof()는 참 (!0)

- 3 : 조건이 참이라 실행 되지만 안에 읽을 정수 없어서 age에 값 저장 안됨

- 4 : age 초기화 안되어 쓰레기 값 출력

 

 

파일이

20

21

22

 

이렇다면

fp 참조 파일에 3명 나이 저장되어 있을 때 데이터가 개행 문자로 나뉘어져 있다면

- 1 ~ 5 : FPI는 파일의 처음을 가리킴

FPI가 가리키는 곳에서 데이터를 읽고 age에 저장하는 것을 반복하나 파일의 데이터 뒤 개행 문자가 있으므로, 데이터를 읽은 후 개행 문자를 가리키게 됨

처음 20 읽고 저장 -> FPI는 그 뒤 개행 문자 가리킴

개행 문자 무시하고 그 뒤 21 읽고 저장 -> FPI는 그 뒤 개행 문자 가리킴

개행 문자 무시하고 그 뒤 22 읽고 저장 -> FPI는 그 뒤 개행 문자 가리킴

개행 문자를 가리키므로 데이터는 끝났으나 while 조건문 !feof(fp)가 아직 참

while문을 한 번 더 반복 함

- 3 : FPI가 읽은 개행 문자는 읽은 후 무시하고 정수 읽으려 하지만 파일 끝 문자 지나게 되고 읽을 정보 없어서 EOF 반환

- 4 : 이 전에 age 저장되었던 마지막 값을 출력. 같은 나이가 또 출력됨

 

(2)   fscanf( ) 함수의 반환 값을 활용

o  fscanf( ) 함수는 파일 끝에 도달하거나 오류가 나면 EOF 반환

o  파일 읽기 시도 한 후 fscanf( ) 함수 반환 값 확인 해 읽기 성공여부 확인 가능

o  선호하는 방법!

o  while (fscanf(fp, “%d”, &age) !=EOF)

printf(“%2d \n, age);

 

4.     문자 단위 파일 입출력

n  파일에 저장된 모든 데이터는 연속된 바이트로 구성, 어떠한 파일도 바이트 단위로 쓰고 읽기 가능

 

1)    문자 단위로 파일에 쓰기 : fputc( )함수

u  문자 단위로 씀

u  fputc(문자, 파일 포인터 변수명);

문자를 파일 포인터 변수가 가리키는 파일에 씀

fputc(‘a’, fp);

u  fputc(정수, 파일 포인터 변수명);

ASCII 코드 값이 정수에 해당하는 문자 한 개를 파일 포인터 변수가 가리키는 파일에 씀

fputc(67, fp);

 

2)    문자 단위로 파일 읽기 : fgetc( )함수

u  파일에서 문자 한 개를 읽어 반환

u  fgetc(파일 포인터 변수명);

o  반환형을 읽은 문자의 ASCII코드 값이 반환됨 -> int

o  읽기 오류 발생하거나 파일 끝에 도달하면 -1에 해당하는 EOF상수 반환

o  char ch;

FILE *fp = fopen(“data.txt”, “r”);

ch = fgetc(fp);

 

5.     문자열 단위 파일 입출력

n  텍스트 파일에 저장된 내용을 문자열 단위로 입출력 함수 fputs( ), fgets( )

n  puts( ), gets( )와 개행 문자 다루는 데 있어 차이가 있음 ! 주의 필요

1)    문자열 단위 출력 : fputs( )함수

u  문자열 단위로 파일 쓰기

u  자동으로 개행 문자 넣지 않음

u  fputs(문자열 시작 주소, 파일 포인터 변수명);

o  문자열 시작 주소에 저장된 문자열을 파일 포인터에 연결된 파일에 씀

o  문자열의 끝을 나타내는 널문자 파일에 쓰지 않음

o  개행 문자 자동으로 추가 X

o  출력 성공하면 출력한 바이트 수 반환, 실패하면 EOF 반환

u  fputs(“문자열 단위 출력 \n”, fp); 처럼 같이 출력할 문자열에 포함된 개행 문자는 출력

 

2)    문자열 단위 출력 : fgets( )함수

u  파일에 쓰여진 개행 문자까지 문자열에 포함시킴

u  한 번에 읽을 수 있는 문자열 길이 정해져 있어 행이 길면 행 전체를 못 읽을 수도 있음

o  한 행 단위로 읽고 싶으면 최대 입력 문자 수를 충분히 크게 지정

u  fgets(문자열 저장 주소, 최대 입력 문자 수, 파일 포인터 변수명)

o  파일 포인터에 연결된 파일에서 (최대 입력 문자수 – 1)개의 문자 읽은 후 뒤에 널문자(\0) 합친 문자열을 지정한 문자열 저장 주소부터 저장

o  최대 입력한 문자 개수만큼 읽지 않았지만 중간에 개행 문자(\n)읽으면 읽기 쥥단하고 뒤에 널문자 합친 문자열 저장 -> 개행문자도 문자열에 포함

o  파일 끝에 도달하거나 오류 발생시 NULL포인터 반환

 

2절  이진 파일 입출력

l  텍스트 파일은 모든 데이터가 문자열로 변환되어 기록됨

n  fprintf( ) : 정수를 문자로 변환하여 파일에 기록

n  fscanf( ) : 파일에서 문자로 된 숫자를 읽어 정수로 변환하여 변수에 저장

 

l  이진 파일은 수치 데이터가 문자로 변환되지 않고 곧바로 수치로 저장됨

n  수치를 읽을 때 한 개의 수치로 바로 읽음 -> 수치와 문자열 간 변환 과정 없음

n  읽고 쓰기 빠름 / 저장 공간 적게 차지(정수의 경우 언제나 4바이트 이므로)

n  컴퓨터 기종이 다를 경우 수치 표현 방식이 다를 수 있음 -> 내용 달라질 수 있음

 

l  이진 파일은 행으로 분리되지 않음

n  행의 끝 표시할 필요 없음

n  널 문자, 개행 문자 같은 글자들도 특별한 의미 없이 데이터로 취급

n  눈으로 내용을 확인하기 어려우므로 특정 프로그램 사용해야 함

 

l  FILE *fp = fopen(“파일명”, “wb/rb/ab”);

n  형태 모드 주의!

u  wb : 이진 파일 쓰기 전용

u  rb : 이진 파일 읽기 전용

u  ab : 이진 파일 추가 전용

 

1.     이진 파일에 쓰기 : fwirte( ) 함수

n  블록 (block 바이트 단위의 연속된 데이터 집합)으로 파일 씀

u  일정한 크기의 데이터를 통째로 읽거나 쓸 수 있음

n  fwrite( )함수 이용해 만들어진 파일에서 데이터 읽어올 때 블록 크기에 주의해서 정확한 크기의 블록단위로 읽어와야 함

n  fwrite(데이터 시작 주소, 블록 크기, 블록 개수, 파일 포인터 변수명);

u  데이터 시작 주소부터 저장된 (블록 크기 * 블록 개수) 바이트의 데이터를 파일 포인터 변수에 연결된 이진 파일에 쓴 후 파일에 쓴 블록 개수 반환

u  블록 크기 : 바이트 단위 / 블록 개수 : 정수

u  이진 파일에 쓰는 데이터 형은 달라도 됨. 이진 파일에서 읽어올 때 데이터 기록한 순서와 정확이 일치하도록 읽어와야 함

int age[10] = {20,21,22,23,24,25,26,27,28,29}

fwrite(age, sizeof(int), 10, fp);

double height = 175.5;

fwrite(height, sizeof(double), 1, fp);

 

2.     이진 파일에 읽기 : fread( ) 함수

n  이진 파일에서 데이터 블록 읽어 오는 함수

n  fread (데이터 저장 시작 주소, 블록 크기, 블록 개수, 파일 포인터 변수명);

u  파일 포인터 변수에 연결된 파일에서  (블록 크기 * 블록 개수) 바이트의 데이터를 읽어서 시작 주소에 저장 후 읽은 블록 개수 반환

u  블록 크기 : 바이트 단위 / 블록 개수 : 정수

u  데이터 저장 시작 주소에 해당하는 기억장소는 (블록 크기 * 블록 개수) 바이트의 데이터 저장하기에 충분한 기억장소여야 함

 

n  int age[10];

FILE *8fp = fopen(“data.bin”, “rb”);

fread(age, sizeof(int), 10, fp);

 

3절  파일의 임의 접근

l  임의 접근 : 파일 읽기/ 쓰기를 순서대로 X -> 임의의 위치에서 바로 읽기/쓰기 할 수 있는 접근 방식

l  파일 위치 지시자 조작하는 함수로 읽기 쓰기 시작 위치 조정 -> 커서

 

1.     파일 위치 지시자 이동하기 : fseek( ) 함수

n  fseek(파일 포인터 변수명, 오프셋, 기준점)

u  파일 위치 지시자가 기준점으로부터 오프셋만큼 떨어진 곳을 가리키게 함

u  읽기 쓰기 시작 위치 = (기준점 + 오프셋) 바이트 위치

u  이동에 성공하면 0 반환, 실패하면 0이 아닌 값 반환

 

n  기준점

u  SEEK_SET : 0. 파일의 시작 지점 의미

u  SEEK_CUR : 1. 파일의 현재 지점 의미

u  SEEK_END : 2. 파일의 끝 지점 의미

 

n  오프셋 : long형 정수. 기준점 이전이면 음수 / 기준점 이후면 양수 사용

 

n  fseek(fp, 100, SEEK_SET);

 fseek(fp, 100, SEEK_CUR);

 fseek(fp, -100, SEEK_END);


 

2.     rewind( ) 함수

n  rewind(포인터 변수명)

파일 포인터에 연결된 파일의 다음 읽기/쓰기 위치를 파일의 시작 지점으로 이동

= fseek(fp, 0, SEEK_SET);

 

3.     ftell( ) 함수

n  현재 파일의 읽기/ 쓰기 위치 알려줌 (파일 위치 지시자(FPI)가 가리키는 곳을 알려줌)

n  파일의 시작 위치가 상대적으로 0

현재 FPI가 가리키는 곳이 파일의 시작위치로부터 몇 바이트 떨어져 있는지 반환

n  ftell(파일 포인터 변수명)

position = ftell(fp);


+ Recent posts