카테고리 없음

CHAPTER 15. 파일 처리

모루우 2025. 12. 17. 07:55
728x90
반응형

15.1 파일 기초

텍스트파일과 이진파일

보조기억장치인 디스크에 저장되는 파일(file)은 직접 삭제하지 않는 한 프로그램이 종료되더라도 계속 저장됨

프로그램에서 사용하던 정보를 종료 후에도 계속 사용하고 싶다면 프로그램에서 파일에 그 내용을 저장해야 함

 

텍스트 파일: 문자 기반의 파일로서 내용이 아스키코드(ascicode)와 같은 문자 코드 값으로 저장됨

메모리에 저장된 실수와 정수 같은 내용도 텍스트 파일에 저장될 때는 문자 형식으로 변환되어 저장됨

 

이진 파일: 텍스트 파일과 다르게 그림 파일, 동영상 파일, 실행 파일과 같이 각각의 목적에 알맞은 자료가 이진 형태(binary format)로 저장되는 파일

프로그램 내부 형식으로 저장되는 파일

자료는 메모리 자료 내용에서 어떤 변환도 거치지 않고 그대로 파일에 기록되므로 텍스트 파일에 비해 속도가 빠르다

 

입출력 시 이동 통로가 바로 입출력 스트림(io stream)임 

키보드에서 프로그램으로 자료가 이동하는 경로가 바로 표준입력 스트림이며 함수 scanf()는 표준입력 스트림에서 자료를 읽을 수 있는 함수

프로그램에서 모니터의 콘솔로 자료가 이동하는 경로가 표준출력 스트림이며 함수 printf()는 표준출력 스트림으로 자료를 보낼 수 있는 함수

다른 곳에서 프로그램으로 들어오는 경로가 입력 스트림(input stream)

자료가 떠나는 시작 부분이 자료 원천지(data source) 키보드이면 표준입력

프로그램에서 다른 곳으로 나가는 경로가 출력 스트림(output stream)

자료의 도착 장소는 자료 목적지(data destination) 콘솔이면 표준출력

 

프로그램에서 보조기억장치에 파일로 정보를 저장하거나 파일에서 정보를 참조하려면 파일(file)에 대한 파일 스트림(file stream)을 먼저 연결 해야 함

파일 스트림이란 보조기억장치의 파일과 프로그램을 연결하는 전송경로

파일 스트림은 입력을 위한 파일 입력 스트림(file input stream)과 출력을 위한 파일 출력 스트림(file output stream)으로 나뉠 수 있음

 

프로그램에서 특정한 파일과 파일 스트림을 연결하기 위해서는 함수 fopen() 또는 fopen_s()를 이용 

둘은 stdio.h에 정의되어 있음

 

FILE * fopen(const char * _Filename, const char * _Mode);

errono_t fopen_s(FILE ** _FILE, const char * _Filename, const char * +_Mode);

 

fopen()은 _Filename의 파일 스트림을 모드 _Mode로 연결하는 함수이며 스트림 연결에 성공하면 파일 포인터를 반환하며, 실패하면 NULL을 반환

fopen_s()는 스트림 연결에 성공하면 첫번째 인자인 _File에 파일 포인터가 저장되고 정수 0을 반환하며, 실패하면 양수를 반환함

C는 값 복사 방식이기 때문에 fopen_s()는 함수 내부에서 파일 포인터(fp)의 값을 변경해야 하므로 fp의 값이 아니라 fp의 주소를 넘겨야 함 그래야 fp가 바뀌기 때문에

FILE*는 디스크 파일이 아니라 디스크 파일과의 연결 정보를 담은 구조체를 가리키는 포인터

파일 그자체는 디스크에 있는 데이터로 C가 이 데이터를 직접 다룰 수는 없다

C가 파일을 사용하려면 FILE 구조체(스트림)가 필요하다

파일 구조체의 주소가 FILE *fp

즉 fopen_s는 FILE 구조체를 가리키는 포인터를 바꿔야 함

처음에 fp는 아무것도 가리키지 않기 때문에 fp가 그 구조체를 가리키도록 값을 바꿔줘야 한다

fp = (FILE 구조체의 주소)

파일 그 자체는 디스크에 있는 데이터고 그 파일을 여는 동작은 OS과 관리함

프로그램이 할 수 있는 것은 파일을 OS에 요청해서 열고 OS가 만들어 준 FILE 스트림을 받고 그 스트림(FILE *)을 사용해 파일에 접근

즉 프로그램은 보안, 안정성, 플랫폼 독립성을 이유로 FILE 구조체에 직접 접근 할 수 없다

즉 FILE *fp;를 선언하고 fp가 가리키는 주소 자체를 바꿔야 하므로 FILE **fp로 주소를 넘겨줘서 fp의 값을 바꿔준다 파일을 가리키는 주소로

 

파일 스트림 열기

함수 fopen()으로 파일 스트림 열기

프로그램에서 특정 파일과 파일 스트림을 연결하기 위해서는 함수 fopen() 또는 fopen_s()를 이용한다

 

함수 fopen_s()는 파일 스트림 연결에 성공하면 정수 0을 반환. 만일 스트림 연결에 실패하면 양수를 반환

 

텍스트 파일인 경우 r, w, a 등의 종류가 있고

읽기 모드 r은 읽기가 가능한 모드이며, 쓰기는 불가능

쓰기모드 w는 파일 어디에든 쓰기가 가능한 모드이나 읽기는 불가능

추가모드 a는 파일 중간에 쓸 수 없으며 파일 마지막에 추가적으로 쓰는 것만 가능한 모드, 읽기는 불가능

파일모드 a에서 파일에 쓰는 내용은 무조건 파일 마지막에 추가됨

 

힘수 fclose()로 파일 스트림 닫기

파일 처리가 모두 끝났으면 파일 포인터 f를 인자로 함수 fclose()를 호출하여 반드시 파일을 닫아야 함

함수 fclose()는 내부적으로 파일 스트림 연결에 할당된 자원을 반납하고 파일과 메모리 사이에 있던 버퍼의 내용을 모두 지우는 역할을 수행

 

파일이 쓰기 모드로 열리지 않으면 함수 exit()을 이용하여 프로그램을 종료

exit()을 이용하려면 헤더 파일 stdlib.h가 필요하며 함수 exit()은 함수를 강제로 종료하는 기능을 수행함 인자 값 0은 정상적인 종료를 의미하고 0이 아닌 값은 정상적인 종료가 아님을 운영체제에게 알리는 의미로 사용

 

15.2 텍스트 파일 입출력

텍스트 파일에 자료를 쓰거나 읽기 위하여 함수 fprintf() 또는 fscanf_s()를 이용

int fprintf(FILE * _File, const char * _Format, ...)

int fscanf(FILE * _File, const char * _Format, ...)

int fsanf_s(FILE * _File, const char * _Format, ...)

_File은 서식화된 입출력 스트림의 목적지인 파일, _Format은 입출력 제어 문자열이며 이후 기술되는 인자는 여러 개의 출력될 변수 또는 상수

fprintf(stdout, "제어문자열", ...)은 printf("제어문자열",...)와 같이 표준출력 기능을 수행

기호 상수 stdin, stdout은 stderr과 함께 헤더 파일 stdio.h에 정의되어 있는 값으로 각각 표준입력, 표준출력, 표준에러를 의미 

함수 scanf_s()에서 표준입력을 빈칸으로 구분하므로 중간에 공백이 없는 이름을 입력해야 함

함수 scanf_s()는 이전 함수인 scanf()와 다르게 형식제어문자 %s를 사용하는 문자열 입력에 저장되는 버퍼와 함께 버퍼의 크기인 인자를 하나 더 삽입해야 함

 

stdin 키보드 입력을 파일처럼 읽는 스트림

키보드 말고 다른 입력도 연결될 수 있음

 

파일 f에서 함수 fscanf_s()를 이용하여 구조체의 정보를 입력하려면 파일의 내부 자료의 저장 형태를 알아야 한다

 

파일 문자열 입출력

함수 fgets()와 fputs()

함수 fgets()는 파일로부터 한 행의 문자열을 입력받는 함수

함수 fputs()는 파일로 한 행의 문자열을 출력하는 함수

 

char * fgets(char * _Buf, int _MaxCount, FILE * _File);

첫 번째 인자는 문자열이 저장될 문자 포인터이고, 두 번째 인자는 입력할 문자의 최대 수이며, 세 번째 인자는 입력 문자열이 저장될 파일

 

int fputs(char * _Buf, FILE * _File);

첫 번째 인자는 출력될 문자열이 저장된 문자 포인터이고, 두 번째 인자는 문자열이 출력되는 파일

 

feof()와 ferror()

feof()는 파일 스트림의 EOF(End of File) 표시를 검사하는 함수

함수 ferror()는 파일 처리에서 오류가 발생했는지 검사하는 함수

이전 파일 처리에서 오류가 발생하면 0이 아닌 값을 반환하고, 오류가 발생하지 않으면 0을 반환

함수 feof()는 읽기 작업이 파일의 이전 부분을 읽으면 0을 반환하고 그렇지 않으면 0이 아닌 값을 반환

파일 스트림의 EOF는 이전 읽기 작업에서 EOF 표시에 도달하면 0이 아닌 값으로 지정

단순히 파일 지시자가 파일의 끝에 있더라도 feof()의 결과는 0이다 

 

파일 스트림에는 상태(flag)가 있음 

파일을 읽다가 "끝에 도달하면" EOF 플래그가 켜짐

> 파일 스트림의 EOF는 이전 읽기 작업에서 EOF 표시에 도달하면 0이 아닌 값으로 지정

EOF 플래그가 켜지면 이후 읽기 작업은 계속 EOF만 나옴

 

feof()는 "읽기 실패 후 상태 확인용"

입력 루프가 끝났을 때

루프 종료 이유가

EOF인지

에러(ferror)인지

다른 이유인지

확인하고 싶을 때

 

feof()는 EOF 플래그가 켜졌는지 검사하는 함수

feof()는 파일 끝에 도달한 상태에서 읽기를 시도했을 때만 true가 됨 

단순히 파일 끝에 도달했다고 해서 feof()가 true가 되는 건 아님

fgets()로 조건문을 써야 하는 이유는 fgets()는 NULL을 반환한 즉시 반복문이 꺼지지만 feof()는 fgets()가 NULL을 반환해야 플래그가 켜지고 그러면 NULL 값이 남기 때문에

 

fgets()를 조건문으로 쓰는 것과 차이점은 feof()는 EOF에서 NULL을 반환하여 반복문에 진입을 하지 않지만 

feof()는 EOF에서 0을 출력하고 EOF를 지났을 때 -1을 출력한다

 

파일 문자 입출력

함수 fgetc()와 fputc() 함수원형

함수 fgetc()와 getc()는 파일로부터 문자 하나를 입력 받는 함수

함수 fputc()와 putc()는 문자 하나를 파일로 출력하는 함수

이 함수들은 문자 하나의 입출력의 대상인 파일 포인터를 인자로 이용

 

int fgetc(FILE * _File);

int fputc(int _Ch, FILE * _File);

 

15.3 이진 파일 입출력

함수 fprintf()와 fscanf(), fscanf_s()는 자료의 입출력을 텍스트 모드로 처리

이진 파일은 c언어의 자료형을 모두 유지하면서 바이트 단위로 저장되는 파일

이진 모드로 블록 단위 입출력을 처리하려면 함수 fwrite(), fread()를 이용

 

이진 파일은 문자코드(ASCII, UTF-8)로 변환하지 않고 값 자체를 비트 단위로 저장

 

size_t fwrite(const void * _Buffer, size_t _ElementSize, sie_t _ElementCount, FILE* _Stream);

size_t fread(void * _Buffer, size_t _ElementSize, size_t _ElementCount, FILE* _Stream);

 

fread, fwrite는 읽고 쓰고 하면 이동함

 

_Buffer가 가리키는 메모리에서 _ElementSize만큼 _ElementCounter개를 파일 _Stream에 쓰는 함수

반환값은 성공적으로 입출력을 수행한 항목의 수

 

이진 파일을 위한 열기 모드에서 문자 'b'를 추가할 수 있음

rb, wb, ab 이진 파일의 읽기, 쓰기, 추가 모드로 파일을 연다

 

구조체의 파일 입출력

 

15.4 파일 접근 처리

순차 접근과 임의 접근

파일을 열면 위치(file position)는 항상 파일의 시작 부분을 가리킨다

파일 위치는 파일 내부를 바이트 단위의 파일 내부 위치

이 파일 위치를 파일 지시자 또는 파일 표시자라고 부른다

파일의 시작점에서 파일 위치는 0이며 1바이트마다 1씩 증가한다

파일의 마지막에는 파일의 마지막을 알리는 EOF 표시가 있음

 

파일 위치는 파일 내부에서 자료를 읽거나 쓰는 만큼 파일의 현재 위치에서 뒤로 이동

 

파일 스트림 연결시 파일 위치

파일을 처음으로 열면 모드에 관계없이 파일 위치는 모두 0

추가 모드 'a'에서는 처음 오픈 시 시작 위치에 있다가 쓰기를 시작하면 자동으로 파일 마지막으로 이동하여 추가

 

순차적 접근(sequential access): 파일 위치를 처음부터 하나씩 증가시키면서 파일을 참조하는 방식

임의 접근 (random access): 파일의 어디라도 바로 참조하는 방식

함수 fseek()

파일의 임의 접근을 처리하기 위해서는 파일 위치를 자유 자재로 이동하는 함수 fseek()이 필요

fseek(FILE * _File, long _Offset, int _Origin);

파일 _File의 기준점 _Origin에서 _Offset만큼 파일 포인터를 이동하는 함수, 성공하면 0을 반환하며 실패하면 0이 아닌 정수를 반환

Origin에는 기준점으로 정수형 기호 상수로 SEEK_SET(파일의 시작 위치), SEEK_CUR(파일의 현재 위치), SEEK_END(파일의 끝 위치) 이 3가지 중 하나를 쓸 수 있음

 

함수 ftell()은 인자인 파일의 파일 위치를 반환

함수 rewind()는 파일 위치를 무조건 가장 앞으로 이동

 

fopen()과 fopen_s()의 인자인 파일열기 종류(모드)에는 텍스트 파일인 경우 r, w, a, r+, w+, a+ 등의 종류

 

파일 모드에서 +의 삽입은 수정(update) 모드 의미로 원래의 모드에서 읽기 또는 쓰기가 추가되는 모드

수정(update) 모드에서는 모드 간의 전환이 가능하다

수정 모드에서 모드 전환은 추가 모드와 읽기 모드 간의 전환과 쓰기 모드와 읽기 모드 간의 전환(mode switch)이 가능하다 모든 파일 모드 전환 사이에는 fseek() 또는 rewind()와 같은 함수 호출이 반드시 필요하다

모드 전환시에는 fflush(), fsetpos(), fseek() 또는 rewind()와 같은 함수 호출이 반드시 필요

 

특정 파일을 대상으로 하는 입출력 함수는 대부분 헤더 파일 stdio.h에 그 함수 원형이 정의되어 있음

문자

입력: int getchar(void) / int getc(FILE *), int fgetc(FILE *)

출력: int putchar(int) / int putc(int, FILE *), int fputc(int, FILE *)

>> getchar()의 매개변수는 void인 이유는 getchar는 아무 인자도 받지 않고 stdin에서 1문자를 읽기 때문

사용자가 어디에서 읽을지 지정할 필요가 없음 putchar()의 매개변수가 int인 이유는 EOF(-1)를 표현하기 위해서 즉 문자 범위와 -1을 표현하기 위해서 int로 받음

문자열

입력: char *gets(char *) / char * fgets(char *, int, FILE *)

출력: int puts(const char *) / int fputs(const char *, FILE *)

서식 자료

입력: int scanf(const char *, ...), int scanf_s(const char *, ...) / int fscanf(FILE *, const char *, ...), int fscanf_s(FILE *, const cahr *, ...)

출력: int printf(const char *, ...) / int fprintf(FILE *, const char *, ...)

 

fscanf()는 딱 정해진 서식만큼의 문자를 읽는다 %s는 공백을 만나기 전까지의 연속된 문자열만 읽는다

 

함수 _getw(), _putw()는 워드(word) 크기의 int형 정수를 파일에 이진 모드로 입출력하는 함수

* 여기서 워드 크기는 OS와 컴파일러의 int 크기를 의미

CPU의 워드는 한 번에 처리하는 기본 단위로 8바이트(64bit CPU), 4바이트(32bit CPU)

C함수의 워드는 시스템에서 int의 크기(대부분 4바이트)

형태

int _getw(FILE *)

int _putw(int, FILE *)

 

파일 처리 함수 remove()와 rename()

remove()는 지정된 특정한 파일을 삭제하고, 함수 rename()은 지정된 파일 또는 폴더의 이름을 새로운 이름으로 바꾸는 기능을 수행함

int remove(char const* _FileName);

>> 파일이 성공적으로 삭제되면 0을 반환하며, 실패하면 -1을 반환한다

int remove(char const* _OldFileName, char const* _NewFileName);

>> 성공적으로 이름이 수정되면 0을 반환하며, 실패하면 0이 아닌 정수를 반환한다

 

&data는 배열 전체를 가리키는 포인터

 

 

728x90
반응형