파일 처리 함수

코딩하는 기린·2022년 3월 7일
0

C

목록 보기
12/13

표준 입출력 함수(printf(), scanf(), ...)는 키보드와 모니터를 통해 자료를 입출력합니다.
하지만 '파일 처리 함수'는 ssd, 하드디스크, USB 메모리같은 보조 기억장치의 파일(file)에 OS(운영체제)를 통해 자료를 읽고 쓰게됩니다.
파일은 '텍스트 파일(text file)'과 '2진 파일(binary file)' 두가지가 있습니다.
텍스트 파일은 문자로 구성된 파일이며, 2진 파일은 텍스트 파일을 포함해 모든 종류의 자료를 다루는 파일입니다. 2진 파일은 컴파일되어 있으므로 기계어에 가까워 내용의 이해 및 인쇄가 불가능합니다.
C에서는 이러한 파일들과 컴퓨터에 연결된 장치들까지도 모두 파일로 처리합니다.

파일 입출력

'파일 입출력'은 파일에 대한 입력과 출력을 의미합니다.
'파일에 대한 입력'은 보조 기억장치의 파일에 있는 자료를 기억공간에 읽어오는 것 입니다.
'파일에 대한 출력'은 기억공간에 있는 자료를 보조 기억장치의 파일에 읽어오는 것 입니다.
이때 파일 입출력 함수를 사용하는데, 모든 파일 입출력 함수는 파일의 위치를 가리키는 '파일 포인터'를 사용합니다. 그리고 파일 입출력 시 기억공간과 보조 기억장치 사이에 존재하는 '버퍼(buffer)'라는 임시 기억공간을 활용합니다. 버퍼를 사용하는 이유는 기억공간으로 활용되는 주 기억장치와 보조 기억장치 간에 속도 차이때문에 처리시간이 많이 소요되므로, 버퍼의 크기만큼 자료를 일단 채운 뒤, CPU에서 이를 한꺼번에 처리하여 출력해 처리시간을 최소화 시키기 위함입니다.

파일 포인터를 이용한 파일 입출력

프로그램과 입출력 장치(키보드, 모니터) 간에 자료의 입출력을 위해서는 '스트림(stream)'이라고하는 논리적인 통로가 필요합니다.

표준 입출력과 스트림
- 프로그램 <-> 표준 입력(키보드) : '입력 스트림'이 존재하여 표준 입력함수(scanf() 등)을 이용하여 자료의 입력이 가능합니다.
- 프로그램 <-> 표준 출력(모니터) : '출력 스트림'이 존재하여 표준 출력함수(printf() 등)을 이용하여 자료의 출력이 가능합니다.
※ 표준 입출력 시, OS가 자동으로 프로그램이 시작할 때 표준 입출력 장치와의 스트림을 생성하고, 프로그램 종료시 자동으로 스트림을 소멸시킵니다.

파일 입출력 시에도 프로그램과 파일을 연결하는 스트림이 있어야합니다. 그러나 표준 입출력시와 달리, 파일 입출력 시에는 이를 위한 스트림을 수동으로 프로그램을 통해 생성 및 소멸 시켜주어야합니다.

파일 입출력 과정

파일을 엽니다.(스트림 생성) -> 입출력을 수행합니다. -> 파일을 닫습니다.(스트림 소멸)

스트림의 생성(파일 열 때)에는 'fopen()' 함수가 사용되고, 소멸(파일 닫을 때)에는 'fclose()' 함수가 사용됩니다.
파일과 프로그램의 통로 역할을 하는 스트림에는 '파일 포인터'가 사용됩니다.

파일 처리 함수

파일 포인터를 사용하여 파일에 입출력을 수행하는 함수로, 'stdio.h' 헤더파일에 원형이 선언되어있습니다.

함수 기능
fopen() 파일을 지정한 모드로 엽니다.
fclose() 파일을 닫습니다.
fgetc(), getc() 파일로부터 한 문자를 읽습니다.
fputc(), putc() 파일에 한 문자를 씁니다.
fgets() 파일로부터 문자열을 읽습니다.
fputs() 파일에 문자열을 씁니다.
fscanf() 파일로부터 정해진 형식에 따라 읽습니다.
fprintf() 파일에 정해진 형식에 따라 씁니다.
fread() 파일로부터 정해진 크기의 자료를 정해진 갯수만큼 읽습니다.
fwrite() 파일에 정해진 크기의 자료를 정해진 갯수만큼 씁니다.
fseek() 파일에서 입출력 위치를 이동합니다.
feof() 파일의 끝인지를 확인합니다.
ferror() 파일의 입출력 시 에러 발생 유무를 확인합니다.

파일 처리 함수를 사용하여 만들어지는 파일은 그 파일을 구성하는 방법에 따라 '순차 파일(sequential file)'과 '랜덤 파일(random file)'로 나뉩니다.
순차 파일은 파일의 처음부터 자료를 차례대로 읽고 기록하는 파일이며,
랜덤 파일은 파일의 임의 위치에서 자료를 읽고 기록하는 파일입니다.

파일 포인터를 활용한 파일 편집

FILE *fp; // 파일 포인터 fp 선언

fp = fopen("파일명", "파일 사용 모드"); //fp가 파일을 가리키게하고 파일을 지정한 모드로 엽니다.

...

"파일 처리 함수를 활용한 명령문"

...

fclose(fp); //버퍼를 비우고 fp가 가리키는 파일을 닫습니다.
  • 파일 포인터 선언 : 'FILE'형은 구조체로 되어있으며, 파일 내의 위치정보와 파일의 끝에 관한 정보를 갖고있습니다. FILE형으로 선언된 파일 포인터는 버퍼의 어떤 부분을 가리킵니다. 이때 파일 포인터는 동시에 여러개 선언도 가능하며, 각각의 버퍼를 갖습니다.

  • 파일 열기 : 'fopen()' 함수를 사용하며, 정상적으로 입출력 가능한 상태면 지정된 파일의 파일 포인터 시작 주소값을 리턴하고, 비정상적으로 입출력 불가능한 상태면 NULL 에러값을 리턴합니다.
    '파일명'에는 파일의 경로를 적어줍니다.
    '파일 사용 모드'는 자료의 입출력 방식을 의미합니다.

파일 사용 모드 기능 파일이 있을 때 파일이 없을 때
r(read) 파일 읽기 정상 처리 NULL값 리턴
r+ 파일 읽기, 쓰기, 추가 정상 처리 NULL값 리턴
w(write) 파일 쓰기, 추가 이전 내용 덮어씀 새 파일 생성
w+ 파일 읽기, 쓰기, 추가 이전 내용 삭제 새 파일 생성
a(append) 파일 추가 이전 내용 뒤에 추가 새 파일 생성
a+ 파일 읽기, 추가 이전 내용 뒤에 추가 새 파일 생성

텍스트(text) 모드와 2진(binary) 모드
(파일 사용 모드 뒤에 t 또는 b를 붙여서 사용(t는 생략 가능))

  • 텍스트 모드(t) : 프로그램에서 파일로 자료를 입출력할 때 변환이 일어나는 입출력 모드
  • 2진 모드(b) : 프로그램에서 파일로 자료를 입출력할 때 아무런 변환이 일어나지 않는 입출력 모드

fopen() 함수는 파일을 열 수 없을 때 NULL값을 리턴하여 에러가 생기는 경우가 있으므로, 에러가 생길 때를 대비하여 에러 메시지를 띄우고 프로그램을 종료시키는 코드를 함께 작성해야합니다.

FILE *fp;

if((fp=fopen("파일명", "파일 사용 모드")) == NULL){
    fputs("파일을 찾을 수 없습니다.", fp);
    eixt(1);    //프로그램을 강제 종료시키며, 정상 종료는 '0', 비정상 종료는 '0 이외의 값'을 넣어줍니다.
    }
  • 파일 닫기 : 'fclose()'함수를 사용합니다. 스트림을 닫고 버퍼를 비우며, 쓰기 모드일 경우 파일 끝에 파일의 끝을 나타내는 'EOF(End of FILE)'를 표시해 완전한 파일로 만듭니다.

파일 처리 방식

파일은 정보의 집합입니다. 파일은 논리적으로 '레코드(record)' 단위로 이루어지며, 레코드는 다시 '필드(field)'로 구성됩니다.
학교에 학생기록부가 있다면, 학생 기록부는 파일, 그 안에 학생 한명에 해당하는 종이는 레코드, 그 종이에 학생의 이름, 번호 등의 항목은 필드에 해당합니다.
즉, 필드가 모여서 레코드, 레코드가 모여서 파일을 구성합니다.

순차 파일 처리

파일의 입출력 처리에 사용되는 논리적인 기본단위는 레코드입니다. 그런데 자료 특성상 레코드의 길이가 일정하지 않은 경우가 있는데, 이런 파일을 '순차 파일'이라고 합니다.
따라서 순차 파일의 경우 일정하지않은 레코드를 구분해 줄 필요가 있습니다. 이떄 구분 기호로 'CR(Carriage Return)'과 'LF(Line Feed)'를 합쳐서 사용합니다. 따라서 순차 파일 처리시 레코드를 파일에 쓸 때 개행 기호(\n)는 CR/LF로 바꿔 기록하고, 읽을 때는 CR/LF를 개행 기호로 바꿔서 읽습니다.
이러한 변환 과정을 거치는 파일 모드가 '텍스트 모드'이며, 텍스트 모드로 파일 열고 기록할 때는 반드시 개행 문자를 레코드와 레코드 사이에 작성해주어야합니다. 읽을 때는 CR/LF까지 한번에 읽는 것이 좋습니다.
결론적으로, 순차 파일은 순차적으로 기록되고, 순차적으로 읽히는 파일입니다.

순차 파일 쓰기

  • putc() : putc(문자 변수, 파일 포인터 변수); 형식으로 사용합니다.
    호출에 성공하면 '출력된 문자'를 리턴하며, 실패시 'EOF(-1)'을 리턴합니다.

  • fputs() : fputs(문자열 변수, 파일 포인터 변수); 형식으로 사용합니다.
    문자열을 출력하므로 개행 문자를 넣어 레코드 사이를 구분해주어야합니다.
    호출에 성공하면 '음이 아닌 값'을 리턴하며, 실패시 'EOF(-1)'을 리턴합니다.

  • fprintf() : fprintf(파일 포인터 변수, "출력 형식", 변수); 형식으로 사용합니다.
    호출에 성공하면 '출력된 문자 수'를 리턴하며, 실패시 '음수'를 리턴합니다.

순차 파일 읽기

  • getc() : getc(파일 포인터 변수); 형식으로 사용합니다.
    파일 포인터로부터 '한 문자'를 읽어오며, 한 문자를 읽어오면 파일 포인터가 자동으로 1 증가하여 다음 문자를 가리킵니다. 파일의 끝을 만나거나 에러 발생시 'EOF(-1)'을 리턴합니다.

  • fgets() : fgets(문자열 변수, 문자열 길이+1, 파일 포인터 변수); 형식으로 사용합니다.
    파일에 저장된 문자열 자료를 읽을 때 사용하며, 읽어 낼 문자열의 길이를 반드시 적어야합니다. 저장된 문자열에서 끝을 알리는 CR/LF는 개행 문자(\n)로 변환되어 출력되고 마지막에 '\0'이 추가됩니다. 파일의 끝을 만나거나 에러 발생시 'NULL'을 리턴합니다.

  • fscanf() : fscanf(파일 포인터 변수, "입력 형식", 변수); 형식으로 사용합니다.
    파일의 끝을 만나거나 에러 발생시 'EOF(-1)'을 리턴하지만, 일반적으로 fscanf() 함수에서 파일의 끝을 구분할때는 'feof(파일 포인터 변수) 함수'를 함께 사용합니다, feof() 함수는 파일의 끝을 만나면 '0이 아닌 값'을 리턴합니다.

순차 파일 추가

파일 사용 모드를 추가 모드로 바꾼 뒤, 쓰기 함수를 사용하면 파일 끝에 레코드를 추가할 수 있습니다. 추가 모드에서는 해당 파일이 없어도 그 파일명으로 파일을 새로 생성하므로 파일이 없어도 상관 없습니다.

랜덤 파일 처리

순차 파일은 순차적(파일의 처음이나 끝을 이용)으로 처리하지만, 랜덤 파일은 파일의 임의 위치에서 자료를 편집할 수 있습니다. 순차 파일은 레코드 길이가 일정하지 않기때문에 CR/LF로 구분했지만, 랜덤 파일은 각 레코드의 길이가 일정하므로 레코드 구분이 필요 없습니다.
랜덤 파일은 가변 길이가 아닌 고정 길이 레코드를 갖고있으므로 순차적으로 레코드를 차곡차곡 채우지 못해 공간을 비효율 적으로 사용하게되지만, 레코드의 검색이 빠르고 효율적으로 가능합니다.

랜덤 파일 열기

원칙적으로 랜덤 파일을 입출력하기 위해서는 순차 파일과 달리 레코드 구분을 위해 CR/LF가 필요 없으므로 변환 작업을 하지않는 2진 모드를 사용합니다.
2진 파일은 텍스트 파일보다 적은 기억공간을 차지하지만, 특정 프로그램에서는 그 파일을 읽어 들일 수 없습니다. 오로지 2진 파일에 접근할 수 있도록 작성된 프로그램만 읽고 쓸 수 있습니다.
2진 모드는 레코드 길이를 사용자가 결정하므로 레코드 길이가 일정하여 길이를 알고 있으므로 파일 포인터의 위치를 마음대로 옮기면서 입출력을 수행할 수 있습니다.

랜덤 파일 생성

fwrite(포인터형 자료 저장 변수, 레코드 길이, 레코드 갯수, 파일 포인터 변수);의 형태로 사용합니다.
fwrite() 함수는 텍스트 파일을 저장할 때도 사용하지만, 주로 랜덤 파일 처리 시 사용합니다. fputs() 함수처럼 사용 가능하며, 다른 점은 2진 모드로 파일을 열 때 NULL 값을 사용 가능한 것 입니다.(텍스트 모드에서는 NULL 값을 읽거나 쓸 수 없지만, 2진 모드에서는 가능합니다.)

랜덤 파일 읽기

fread(포인터형 읽을 자료 변수, 레코드 길이, 레코드 갯수, 파일 포인터);의 형태로 사용합니다.
fread() 함수는 읽기에 성공하면 '읽은 레코드 수'를 리턴하며, 실패하거나 파일의 끝을 만나면 '다른 값'을 리턴합니다.

랜덤 파일 위치 제어

  • fseek() : fseek(파일 포인터 변수, 이동할 상대 위치, 기준 위치 지정 값);의 형태로 사용합니다.
    fseek() 함수는 랜덤 파일의 특정 위치에서 입출력 가능합니다. 이동할 위치는 상대 위치 개념을 사용합니다.
기준 위치 지정 값 기능
SEEK_SET(== 0) 파일의 시작 위치로 지정
SEEK_CUR(== 1) 현재 파일 포인터의 위치로 지정
SEEK_END(== 2) 파일의 끝 위치로 지정

이동할 상대 위치는 byte 단위이며, +값은 순방향, -값은 역방향으로 이동합니다.

  • ftell() : ftell(파일 포인터 변수);의 형태로 사용하며, 현재 파일 포인터 변수가 위치한 곳이 파일의 처음부터 몇바이트 떨어진 곳인지 알려줍니다.
profile
Coding Giraffe.

0개의 댓글