Transcript Chap17

Name
Title
Company Name
파일처리를 위한 기초 지식
텍스트 방식의 파일 다루기
이진 방식의 파일 다루기
원하는 블록의 위치에서 파일 읽기와 쓰기가 가능한
랜덤 처리 방식
프로그램을 포함하여 데이터를 컴퓨터의 하드디스크에 저장한다는 것은
나중에 다시 사용하기 위함이다.
프로그램을 비롯하여 워드 프로세서로 작성된 문서 그리고 이미지들을
하드디스크에 저장하거나 불러오기 위해서는 파일(file)이라는 단위를
사용한다.
컴퓨터에서 파일을 저장하는 단계는 문서들을 보관할 때 다음과 같은 단계를
거쳐 서랍장에 보관하는 것과 같은 방법을 사용한다.
프로그램이나 데이터를 하드디스크에 저장하는 것은 마치 강의 시간에
중요한 내용들을 노트에 기록하는 것과 같다.
컴퓨터는 전원이 끊어짐과 동시에 RAM이라는 메인 메모리에 기억되었던
내용들이 사라지기 때문에 보관해야할 내용들은 보조 기억장치인
하드디스크에 저장하듯 사람에게 있어서 노트라는 것이 보조 기억장치인
셈이다.
노트에 새로운 내용을 작성하거나, 또는 작성된 내용을 보기 위해서는 먼저
노트를 열어(open)야 한다. 이어서 새로운 내용을 기록해야 한다면 노트의
빈 공간 또는 빈 페이지를 찾아서 기록(write)을 하고, 반면에 기록된 내용을
읽어야 한다면 해당 내용의 위치를 찾아 읽는다(read). 기록하거나 읽는
것이 모두 끝났다면 여러분들은 노트를 덮을(close) 것이다.
파일 처리 단계
C 언어에서 사용하는 모든 입력과 출력은 파일을 읽고 쓰는 것과 같은
방법으로 이루어진다. 그 이유는 C 언어가 키보드나 모니터(화면)를
포함하여 모든 주변 장치들을 파일처럼 취급하기 때문.
이러한 개념을 사용한 이유는 프로그램과 주변장치 사이의 접속
(인터페이스, interface)을 하나의 통일된 방법으로 단순화시켜 사용하는데
있다.
따라서 모든 입력과 출력은 스트림(stream)이라고 하는 공통된 접속
(인터페이스)을 사용하여 파일로 취급되는 주변장치들과 연결된다.
키보드와 화면에 대한 입력과 출력은 매우 빈번하게 일어나므로 파일을
open할 필요 없이 사용이 가능하지만 디스크 상의 파일에 대한 입력과 출력은
함수 fopen을 사용하여 파일을 open해주어야만 사용할 수 있다.
파일 저장방식 : 텍스트 방식(text mode)과 이진 방식(binary mode)
컴퓨터는 모든 데이터들을 2진수로 처리하므로 하드 디스크에 저장된
파일들도 실제로는 0과 1로 표현된 2진수로 저장한다.
그런데 메모장(notepad) 프로그램을 통해 파일을 열어 보면, 어떤 파일은
읽을 수 있는 문자들로 표현(텍스트 방식)되는 반면에 어떤 파일들은 알아
볼 수 없는 이상한 문자들로 표현되는 파일(이진 방식)이 있다.
텍스트 방식으로 처리할 것인지 이진 방식으로 처리할 것인지는 파일
처리의 첫 번째 단계인 파일 열기(open)부분에서 구분해 준다.
예를 들어 12345 라는 정수를 파일로 저장할 때 텍스트 방식을 이용한다면
숫자 하나마다 1 byte 크기의 ASCII 코드로 변환하여 저장하므로 총 5개의
byte가 필요하다.
그러나 정수 12345는 2 byte 크기 공간에 저장할 수 있기 때문에 이진
방식에서는 2 byte로 표현된 정보로 저장할 수 있다. 따라서 숫자로만
이루어진 데이터를 파일에 저장할 경우에는 이진 방식이 더 효율적이다.
그런데 이진 방식으로 저장된 내용을 텍스트 방식의 메모장 프로그램으로
읽으면 1 byte 단위로 읽은 데이터를 ASCII 코드의 문자로 해석하기 때문에
이상한 문자들로 출력되는 것이다.
파일 입력 또는 파일 출력을 하기위해 파일 열기(open)를 한 후에는 실제
데이터를 파일에 저장하거나 파일에 저장된 데이터를 읽기 위해서
포인터(pointer)를 사용한다.
파일처리에 사용하는 포인터를 파일 포인터라고 부르며 파일 포인터는 해당
파일과 관련된 정보가 들어있는 구조체를 가리킨다.
이 구조체는 헤더파일 <stdio.h>에 FILE 이라는 이름의 구조체 형으로 정의되어
있다.
파일 처리 프로그램을 작성할 때 파일 포인터가 사용된다.
파일과 관련된 작업을 하기 위해 제일 먼저 해야 하는 것은 파일 열기(open)
파일 열기가 이루어지고 나서 파일 쓰기(write)나 파일 읽기(read)가 가능하다.
이후 파일이 열려진 상태에서 파일 쓰기나 파일 읽기를 처리하고 모든 작업이
끝났다면 프로그램을 종료하기 전에 파일을 닫아(close)준다.
예를 들어 파일 처리 원시 프로그램이 저장되어 있는 위치(폴더)에
"names.txt"라는 텍스트 파일을 읽는 작업을 처리할 때 또는 "names.txt"라는
텍스트 파일로 출력할 때 다음과 같은 순서로 처리한다.
C 언어에서 파일 입력 또는 파일 출력을 하기위해서 파일 포인터를 사용한다.
파일에 대한 입력과 출력을 하기 이전에 이러한 구조체 형의 포인터 변수를
선언한 다음, 입출력 함수에 대해 포인터만 넘겨줌으로써 파일 처리가
이루어진다. 파일 열기는 함수 fopen을 사용
파일 열기(open)에 실패할 경우 즉, NULL을 반환할 경우에는 파일과 관련된
어떠한 작업도 처리할 수 없으므로 이 경우에는 프로그램을 종료하는 함수
exit을 사용
파일 처리를 위해 파일을 open할 때 오류가 발생하지 않았다면 파일 쓰기나
파일 읽기 작업을 할 수 있는데 이때 파일 입출력 라이브러리 함수를 사용.
파일 입출력 함수들은 파일과 관련된 함수임을 나타나내기 위해서 표준
입출력 함수의 이름 앞에 "file"의 첫 글자인 'f'를 붙인다.
파일 쓰기나 파일 읽기 처리가 모두 끝났다면 프로그램을 종료하기 전에
열려진 파일들을 모두 닫아 주어야 한다. 파일이 닫혀 지지 않은 상태에서는
그 파일을 다시 열수 없다.
구조체 형 FILE은 사용하는 버퍼, 버퍼의 크기와 현재 위치, 접근하고 있는
파일의 이름 등의 정보를 포함하고 있지만 이에 대해서 자세하게 알고 있을
필요는 없다.
고수준의 파일 입출력 함수들은 모두 구조체 형 FILE 의 내용을 참조하여
처리되므로 프로그래머는 이 구조체의 멤버들을 세부적으로 다룰 필요가
없으며, 파일에 대한 입출력을 하기 전에 이러한 구조체를 갖는 포인터
변수를 선언한 다음, 입출력 함수에 대해 포인터만 넘겨줌으로써 파일
처리가 이루어진다.
구조체 형 FILE 표시
파일 처리에는 파일에 저장된 데이터를 순서대로 읽으면서 처리하는 순차
처리 방식과 원하는 위치에서 바로 데이터를 읽거나 쓸 수 있는
랜덤(random) 처리 방식이 있다. 순차 처리 방식은 텍스트 파일을 대상으로
하고, 랜덤 처리 방식은 이진 파일을 대상으로 한다.
이 함수들은 모두 헤더파일 <stdio.h>를 필요로 하므로 별도의 헤더파일을
불러올 필요는 없다.
□ 문자 단위의 파일 출력
파일 출력 즉, 프로그램에서 만들어진 데이터를 파일에 저장하기 위해서는
함수 fopen의 인자로 출력할 파일의 이름과 파일 출력 모드인 "w"(write)를
사용한다.
만약 fopen에 인자로 사용된 파일의 이름과 동일한 파일이 같은 폴더에 이미
존재한다면 이전에 기록된 내용을 모두 지우고 새로운 파일을 생성한다.
문자단위의
파일 출력 함수
키보드로부터 문자를 입력받는 함수
getchar를 사용하며 Enter키가
사용되기 이전까지 입력된 문자를
파일 출력함수 fputc를 이용하여
파일 "chr.txt"에 출력
실행결과
□ 문자 단위의 파일 입력
파일 입력 즉, 파일에 저장된 데이터를 프로그램을 통해 읽기 위해 함수
fopen의 인자로 읽을 파일의 이름과 파일 입력 모드인 "r"을 사용.
만약 fopen에서 읽을 파일이 폴더에 존재하지 않는다면 파일을 열 수
없으므로 오류가 발생하며 이때 fopen은 NULL 값을 반환하며 정상적으로
파일을 열 수 있다면 파일 포인터를 반환
문자단위의
파일 입력 함수
앞서 [예제 17-01]에서 생성한 파일
"chr.txt"를 입력 함수 fgetc를
사용하여 문자 단위로 읽고 그
내용을 화면으로 출력.
EOF는 End Of File의 줄임말로 파일의
끝을 의미한다. 파일로부터
데이터를 읽을 때 만약 데이터를
읽을 수 없는 파일의 끝부분에
도달했다면 읽는 작업을 중단한다.
실행결과
함수 feof를 사용한 예
[예제 17-2]에서는 파일 입력 함수로
fgetc를 사용하였으나 이 예제에서는
getc를 사용하였고 실행 결과는
[예제 17-2]와 동일.
함수 feof 설명
실행결과
문자열이란 2개 이상의 문자가
연속된 문자. 문자열을 파일로
출력하는 함수로는 fputs를 사용.
함수 fputs 설명
실행결과
함수 fgets는 행 단위의 문자열을
읽는데 사용하는 함수
데이터를 문자열로 읽을 때 함수의
인자로 지정한 문자열의 최대 길이
n보다 긴 문자열에 대해서는 n-1
까지의 문자열만 저장하고, 나머지
문자열은 다음 문자열로 읽는다
함수 fgets 설명
실행결과
□ 파일 출력 형식 지정
화면 출력 함수인 printf에서 변수의 데이터 형에 맞게 형식 지정자인 %d, %f
또는 %s등을 사용하여 출력할 데이터의 형식을 지정하는 것과 같은 방식.
fprintf는 함수의 첫 번째 인자로 파일 포인터가 사용되는 것을 제외하고는
그 사용법이 화면 출력함수인 printf와 동일하다.
실행결과
앞의 [Worldcup G조의 득점수]를 구조체로 정의하여 파일에 출력하는
프로그램을 작성하시오.
실습문제 정답
□ 파일 입력 형식 지정
함수 fscanf는 함수의 첫 번째 인자로 파일 포인터가 사용된다는 것 외에
입력함수인 scanf와 사용방법이 동일하다.
실행결과
[실습문제 17.1]에서 사용한 구조체를 이용하여 fscanf로 파일을 읽어
들여 국가와 득점수, 합계를 화면에 출력하는 프로그램을 작성하시오.
실습문제 정답
입력 함수인 scanf를
사용하여 입력 받은
데이터를 파일로
출력하는데 있어서
데이터의 개수가 정해져
있는 경우
다음 입력을 받기
전에 버퍼의 내용을
비우기 위해 함수
fflush를 사용
실행결과
입력 함수인 scanf를
사용하여 입력 받은
데이터를 파일로
출력하는데 있어서
데이터의 개수가 정해지지
않은 경우의 while문
모든 데이터의 입력이
끝났다면 키보드로
Ctrl-Z와 Enter키를
누르는 동작을 두 번
연속한다.
이진 방식의 파일을 만들기 위해서 사용할 수 있는 파일 쓰기 함수로는
fwrite가 있으며, 구조체와 같은 block 단위의 데이터를 처리할 때 사용한다.
함수 fwrite로 만들어진 출력 파일은 읽을 때, 이진 파일 읽기 함수인 fread를
사용한다.
출력 함수 fwrite는 파일 쓰기가 성공적으로 처리되었을 경우 파일에 기록한
block의 개수를 반환하며 입력 함수 fread는 파일 읽기가 성공적으로
처리되었을 경우 읽은 block의 개수를 반환한다.
fread와 fwrite는 구조체 형과 같이 사용자 정의의 데이터 형을 포함한 모든
데이터 형에 사용할 수 있으며, 구조체의 block 단위로 처리할 수 있으므로
편리하게 사용할 수 있다. 예를 들어 다음과 같은 구조체 student에 대해 st라는
구조체 변수가 있다고 한다면 fprintf와 fwrite를 사용하는 경우 다음과 같은
차이가 있다.
이진 파일에서는 데이터의 단위를 block으로 처리하며 선언된 구조체 변수
st를 하나의 block으로 간주한다.
실행결과
[예제 17-10]에서 파일로 출력하는 부분을 사용자 정의함수로 작성하여
완성하시오. 함수의 인자로 구조체 배열을 사용합니다.
실습문제 정답
친구 5명의 정보(이름, 전화번호, 출생한 월)를 구조체로 정의하여
이진파일에 저장하는 프로그램을 작성하시오.
실습문제 정답
함수 fwrite로 만들어진 출력 파일은 읽을 때 이진 파일 읽기 함수인 fread를
사용한다. 입력 함수 fread는 파일 읽기가 성공적으로 처리되었을 경우 읽은
block의 개수를 반환한다.
텍스트 파일은 파일에 저장된 내용을 읽을 때 파일의 처음부터 시작하여
끝부분(EOF)에 도달할 때까지 순차적으로 읽어 나간다.
그러나 이진 파일은 데이터들이 일정한 크기(구조체)를 갖는 block 단위로
데이터를 저장하므로 임의의 위치에 있는 block만을 읽을 수 있다.
또한 이진 파일에 저장된 전체 데이터를 읽을 때에도 텍스트 파일과 같이
파일의 끝부분(EOF)에 도달할 때까지 저장된 block의 순서대로 하나씩
차례대로 읽을 수 있으며, 전체 block 데이터를 한번에 읽을 수도 있다.
전체 block의 데이터를 한번에 읽는 방법은 함수 fread의 사용에서 함수의 인자
n 부분에 파일에 저장된 전체 block의 개수를 지정한다.
만약 파일에 저장된 전체 block의 개수를 모른다면 파일로부터 전체 block의
개수를 계산해 낼 수도 있다.
실행결과
[예제 17-11]에서 화면으로 출력하는 부분을 사용자 정의 함수로 작성하여
완성하시오. 함수의 인자로 구조체 배열을 사용합니다.
실습문제 정답
[실습문제 17.5]에서 생성한 이진파일을 읽어 들여 화면으로 출력하는
부분을 사용자 정의 함수로 작성하여 완성하시오. 함수의 인자로 구조체
배열을 사용합니다.
실습문제 정답
물론 읽을 수 있다.
단, 텍스트 방식에서는 byte 단위로 처리되므로 텍스트 방식으로 저장된
파일을 이진 방식으로 파일을 읽을 때는 fread 대신에 byte 단위의 fgetc를
사용한다.
추가로 파일에서 줄을 바꾸기 위해 입력한 Enter키('\n')에 대해서도 텍스트
방식은 파일에 저장할 때 CR(Carrage return)과 LF(Line Feed)의 제어문자
쌍으로 변환하여 저장하고, 읽을 때는 반대로 처리하지만 이진 방식은 어떤
변환도 사용하지 않는다.
마찬가지로 텍스트 방식에서 파일을 읽을 때 파일의 끝을 나타내는 Ctrl-Z
(EOF)를 만날 때까지만 읽지만 이진 방식에서는 이 또한 하나의 데이터로
인식하므로 읽는 동작을 중단하지 않는다.
따라서 파일을 복사하는 프로그램을 만들 경우에 원본 파일이 텍스트
파일이건 이진 파일이건 이진 방식으로 파일을 open하고 byte 단위로 읽은
다음 다시 byte 단위인 fputc를 사용하여 출력하는 방법을 이용한다.
파일 처리방식은 크게 순차 접근(sequential access) 처리와 랜덤 접근(random
access)처리 두 가지로 나눌 수 있으며 랜덤 접근을 임의 접근이라고도 한다.
예를 들어 카세트테이프에 저장된 마지막 곡을 듣고 싶다면 그 위치까지
테이프를 계속 감아야 하지만 CD의 경우는 그 곡이 시작하는 번호만 입력하면
음악을 들을 수 있다.
순차 접근 처리는 카세트테이프와 마찬가지로 데이터가 있는 위치를 처음
위치에서부터 찾아나가면서 처리하는 방식이고, 랜덤 접근 방식은 CD나
DVD와 같이 원하는 데이터의 위치를 임의로 찾아 처리하는 방식이다.
이진 방식의 파일 처리에서 함수 fwrite나 fread는 같은 크기의 block 단위로
처리한다.
따라서 파일에서 이동하고자 하는 위치 즉, block의 위치를 선택하여
파일로부터 읽거나 파일에 저장할 수 있다.
파일 포인터를 원하는 block의 위치로 이동시킬 때 함수 fseek을 사용한다.
그리고 파일의 시작 위치로부터 현재의 파일 포인터까지의 거리를 byte
크기로 환산해 주는 함수 ftell이 있다.
함수 ftell은 파일의 크기나 파일에 저장된 전체 block의 개수를 계산하는데
사용한다.
함수 fseek : 파일 포인터를 원하는 block의 위치로 이동
함수 ftell : 파일의 시작 위치로부터 현재의 파일 포인터까지의 거리를 byte
크기로 환산
함수 ftell은 파일의 처음(시작)위치에서 현재의 파일 포인터 위치까지의
거리를 byte 크기로 반환. 따라서 파일의 크기를 byte로 표시하거나 파일에 몇
개의 block이 저장되어 있는가를 계산할 때 다음과 같이 사용
다음의 예제는 앞의 [예제 17-10]에서 생성한 이진 파일 "d-group.bin"을 읽어
파일에 몇 개의 block이 저장되어 있는가를 출력하고, 이동하려는 block의
위치를 입력받아 랜덤 접근에 의해 해당 위치의 데이터를 구조체
단위(block)로 읽은 다음 출력하는 프로그램.
실행 결과
프로그램 표시
[실습문제 17.7]의 프로그램을 [예제 17-12]와 같이 랜덤 접근의 포인터
이동을 이용하는 프로그램으로 수정하여 결과를 확인하시오.
실습문제 정답
검색이란 목적에 따라 필요한 데이터들을 찾아내는 것을 말한다.
앞에서 생성한 이진 파일(d-group.bin)에는 각 block 마다 국가명, 승무패의
정보들이 저장되어 있으므로 이러한 항목들에 대해 조건에 맞는 데이터를
찾아내는 것.
검색을 하려면 우선 파일로부터 데이터를 읽은 다음 배열에 저장한다.
이어서 찾고자하는 항목 즉, 구조체 멤버가 국가명(na)이므로 검색하고자
하는 이름을 입력받아 배열에 저장된 데이터와 비교해야 한다.
이때 이름은 문자열로 처리되므로 문자열 비교 함수인 strcmp 또는 strncmp를
사용할 수 있다.
함수 strcmp과 strncmp의 차이는 문자열 전체를 비교하느냐 또는 문자열
중에서 처음 몇 문자(n)만 비교하느냐의 차이이며 함수의 반환 값은 같다.
프로그램에서 요구하는 검색 대상은 이름에 대한 문자열을 비교하는
것이므로 함수 strcmp를 사용하지만 예를 들어 이름 중에서 김씨성이나
박씨성을 가진 사람만을 검색하고자 한다면 한글 1자는 영문 2 byte에
해당하므로 strncmp(name1, name2, 2)과 같이 처음 2개의 문자열만 비교하여
처리할 수 있다.
검색할 이름의 데이터를 찾았다면 해당 block에 저장된 내용을 출력하고, 해당
데이터가 없는 경우에는 "일치하는 데이터 없음!"이라고 출력한다.
데이터를 파일로부터 읽고, 검색하는 부분은 함수 search_data로 작성하였다.
실행 결과는 검색할 이름으로 "폴란드"를 입력하였고, 검색결과가 출력됨을
확인할 수 있다. 프로그램은 다음 page
실행 결과
[실습문제 17.8]의 프로그램을 친구 이름으로 검색하는 프로그램을
작성하시오.
실습문제 정답
다음 프로그램은 [예제 17-10]에서 생성한 이진 파일(d-group.bin)을 읽은 다음,
데이터를 수정하는 프로그램이며 수정할 데이터는 block 번호로 검색한다.
파일 포인터를 원하는 block의 위치로 이동시킬 때 함수 fseek을 사용한다.
함수 ftell은 파일의 크기나 파일에 저장된 전체 block의 개수를 계산하는데
사용한다.
파일 포인터를 파일의 시작위치로 옮겨야 한다면 함수 fseek 또는 함수
rewind를 사용할 수 있다. 파일 포인터를 파일의 시작위치로 옮길 때
rewind(fp)와 fseek(fp, 0L, SEEK_SET)은 동일한 기능을 한다.
파일 입력과 출력은 파일을 open 할 때 함수 fopen의 파일 모드를 어떤 것을
선택하느냐에 의해 결정되므로 입력과 출력을 번갈아 처리할 수 없다.
따라서 하나의 프로그램에서 파일 입력 후에 파일 출력을 이어서 하고 싶다면
그 사이에 파일을 닫고 다시 출력 모드로 파일을 open하여 사용해야 한다.
이는 파일 입출력 함수들은 buffer를 사용하여 입출력을 처리하기 때문에
입력용 buffer를 다시 출력용 buffer로 사용할 수 없기 때문이다.
그러나 함수 rewind나 fseek을 사용하여 파일 포인터를 시작위치로 옮기면
중간에 파일을 다시 open하거나 닫지 않고도 파일 입력과 파일 출력을
번갈아가며 사용할 수 있다. 함수 rewind는 텍스트 파일과 이진 파일에 대해서
모두 사용할 수 있으나 그 대신 처음에 파일을 open할 때 함수 fopen의 모드에
'+'를 붙여서 사용해야 한다.
입출력 동시모드
실행 결과
다음 프로그램은 이진 파일(d-group.bin)을 읽고, 특정한 데이터(block)를
삭제하는 프로그램을 함수로 작성한 것이다. 단, 삭제할 데이터는 국가명으로
검색.
데이터를 삭제하는 방법은 삭제할 데이터가 위치한 곳을 공백으로 남겨두는
것이 아니라 삭제할 위치에 다른 데이터를 대체해 넣는 것이다.
따라서 삭제할 block의 수만큼 전체 block의 개수가 줄어들도록 처리해야
한다.
그런데 데이터의 삭제는 데이터가 입력된 순서를 유지해야 하는 경우와
그렇지 않은 경우로 나누어서 생각할 수 있다.
만약 두 번째 block의 미국(block number는 1번)의 데이터를 삭제하는 경우에
전체 block의 개수는 3이 되고 입력된 순서를 고려한다면 다음과 같이 나머지
데이터들을 모두 앞부분으로 옮겨야 하는 반면에, 순서를 고려하지 않는다면
제일 마지막 block의 데이터로 대체하는 방법을 사용할 수 있다. 따라서
순서를 고려하지 않는다면 간단한 방법으로 처리할 수 있으므로 이 방법을
사용한다.
데이터를 삭제하는 프로그램은 크게 두 가지 부분으로 나누어서 처리한다.
실행 결과
파일 열기와 닫기
노트에 새로운 내용을 작성하거나, 또는 작성된 내용을 보기 위해서는 먼저
노트를 열어(open)야 한다. 이어서 새로운 내용을 기록해야 한다면 노트의
빈 공간 또는 빈 페이지를 찾아서 기록(write)을 하고, 반면에 기록된 내용을
읽어야 한다면 해당 내용의 위치를 찾아 읽는다(read). 기록하거나 읽는
것이 모두 끝났다면 여러분들은 노트를 덮을(close) 것이다.
파일 저장방식
파일 저장방식 : 텍스트 방식(text mode)과 이진 방식(binary mode)
컴퓨터는 모든 데이터들을 2진수로 처리하므로 하드 디스크에 저장된
파일들도 실제로는 0과 1로 표현된 2진수로 저장한다.
그런데 메모장(notepad) 프로그램을 통해 파일을 열어 보면, 어떤 파일은
읽을 수 있는 문자들로 표현(텍스트 방식)되는 반면에 어떤 파일들은 알아
볼 수 없는 이상한 문자들로 표현되는 파일(이진 방식)이 있다.
텍스트 방식으로 처리할 것인지 이진 방식으로 처리할 것인지는 파일
처리의 첫 번째 단계인 파일 열기(open)부분에서 구분해 준다.
파일 데이터와 파일 포인터
파일 입력 또는 파일 출력을 하기위해 파일 열기(open)를 한 후에는 실제
데이터를 파일에 저장하거나 파일에 저장된 데이터를 읽기 위해서
포인터(pointer)를 사용한다.
파일처리에 사용하는 포인터를 파일 포인터라고 부르며 파일 포인터는 해당
파일과 관련된 정보가 들어있는 구조체를 가리킨다.
이 구조체는 헤더파일 <stdio.h>에 FILE 이라는 이름의 구조체 형으로 정의되어
있다.
파일 처리 프로그램을 작성할 때 파일 포인터가 사용된다.
텍스트 방식의 파일 다루기
파일과 관련된 작업을 하기 위해 제일 먼저 해야 하는 것은 파일 열기(open)
파일 열기가 이루어지고 나서 파일 쓰기(write)나 파일 읽기(read)가 가능하다.
이후 파일이 열려진 상태에서 파일 쓰기나 파일 읽기를 처리하고 모든 작업이
끝났다면 프로그램을 종료하기 전에 파일을 닫아(close)준다.
예를 들어 파일 처리 원시 프로그램이 저장되어 있는 위치(폴더)에
"names.txt"라는 텍스트 파일을 읽는 작업을 처리할 때 또는 "names.txt"라는
텍스트 파일로 출력할 때 다음과 같은 순서로 처리한다.
파일 열기에 실패한 경우
파일 열기(open)에 실패할 경우 즉, NULL을 반환할 경우에는 파일과 관련된
어떠한 작업도 처리할 수 없으므로 이 경우에는 프로그램을 종료하는 함수
exit을 사용
파일 읽기(입력, read)와 파일 쓰기(출력, write)
파일 처리를 위해 파일을 open할 때 오류가 발생하지 않았다면 파일 쓰기나
파일 읽기 작업을 할 수 있는데 이때 파일 입출력 라이브러리 함수를 사용.
문자 단위의 파일 출력
키보드로부터 문자를 입력받는 함수
getchar를 사용하며 Enter키가
사용되기 이전까지 입력된 문자를
파일 출력함수 fputc를 이용하여
파일 "chr.txt"에 출력
문자 단위의 파일 입력
파일 "chr.txt"를 입력 함수 fgetc를
사용하여 문자 단위로 읽고 그
내용을 화면으로 출력.
EOF는 End Of File의 줄임말로 파일의
끝을 의미한다. 파일로부터
데이터를 읽을 때 만약 데이터를
읽을 수 없는 파일의 끝부분에
도달했다면 읽는 작업을 중단한다.
문자열 단위의 파일 출력
문자열이란 2개 이상의 문자가
연속된 문자. 문자열을 파일로
출력하는 함수로는 fputs를 사용.
문자열 단위의 파일 입력
함수 fgets는 행 단위의 문자열을
읽는데 사용하는 함수
데이터를 문자열로 읽을 때 함수의
인자로 지정한 문자열의 최대 길이
n보다 긴 문자열에 대해서는 n-1
까지의 문자열만 저장하고, 나머지
문자열은 다음 문자열로 읽는다
입출력 형식을 지정하는 파일출력
입출력 형식을 지정하는 파일입력
이진 방식의 파일 다루기
이진 방식의 파일 출력
이진 방식의 파일을 만들기 위해서 사용할 수 있는 파일 쓰기 함수로는
fwrite가 있으며, 구조체와 같은 block 단위의 데이터를 처리할 때 사용한다.
함수 fwrite로 만들어진 출력 파일은 읽을 때, 이진 파일 읽기 함수인 fread를
사용한다.
출력 함수 fwrite는 파일 쓰기가 성공적으로 처리되었을 경우 파일에 기록한
block의 개수를 반환하며 입력 함수 fread는 파일 읽기가 성공적으로
처리되었을 경우 읽은 block의 개수를 반환한다.
이진 방식의 파일처리와 구조체
fread와 fwrite는 구조체 형과 같이 사용자 정의의 데이터 형을 포함한 모든
데이터 형에 사용할 수 있으며, 구조체의 block 단위로 처리할 수 있으므로
편리하게 사용할 수 있다. 예를 들어 다음과 같은 구조체 student에 대해 st라는
구조체 변수가 있다고 한다면 fprintf와 fwrite를 사용하는 경우 다음과 같은
차이가 있다.
이진 파일에서는 데이터의 단위를 block으로 처리하며 선언된 구조체 변수
st를 하나의 block으로 간주한다.
이진 방식의 파일 입력
함수 fwrite로 만들어진 출력 파일은 읽을 때 이진 파일 읽기 함수인 fread를
사용한다. 입력 함수 fread는 파일 읽기가 성공적으로 처리되었을 경우 읽은
block의 개수를 반환한다.
이진 방식의 파일 입력과 block 단위
텍스트 파일은 파일에 저장된 내용을 읽을 때 파일의 처음부터 시작하여
끝부분(EOF)에 도달할 때까지 순차적으로 읽어 나간다.
그러나 이진 파일은 데이터들이 일정한 크기(구조체)를 갖는 block 단위로
데이터를 저장하므로 임의의 위치에 있는 block만을 읽을 수 있다.
또한 이진 파일에 저장된 전체 데이터를 읽을 때에도 텍스트 파일과 같이
파일의 끝부분(EOF)에 도달할 때까지 저장된 block의 순서대로 하나씩
차례대로 읽을 수 있으며, 전체 block 데이터를 한번에 읽을 수도 있다.
전체 block의 데이터를 한번에 읽는 방법은 함수 fread의 사용에서 함수의 인자
n 부분에 파일에 저장된 전체 block의 개수를 지정한다.
만약 파일에 저장된 전체 block의 개수를 모른다면 파일로부터 전체 block의
개수를 계산해 낼 수도 있다.
랜덤 처리방식
파일 처리방식은 크게 순차 접근(sequential access) 처리와 랜덤 접근(random
access)처리 두 가지로 나눌 수 있으며 랜덤 접근을 임의 접근이라고도 한다.
예를 들어 카세트테이프에 저장된 마지막 곡을 듣고 싶다면 그 위치까지
테이프를 계속 감아야 하지만 CD의 경우는 그 곡이 시작하는 번호만 입력하면
음악을 들을 수 있다.
순차 접근 처리는 카세트테이프와 마찬가지로 데이터가 있는 위치를 처음
위치에서부터 찾아나가면서 처리하는 방식이고, 랜덤 접근 방식은 CD나
DVD와 같이 원하는 데이터의 위치를 임의로 찾아 처리하는 방식이다.
랜덤 처리방식에 사용하는 함수들
함수 fseek : 파일 포인터를 원하는 block의 위치로 이동
함수 ftell : 파일의 시작 위치로부터 현재의 파일 포인터까지의 거리를 byte
크기로 환산
랜덤 처리방식에 전체 block 수의 계산
함수 ftell은 파일의 처음(시작)위치에서 현재의 파일 포인터 위치까지의
거리를 byte 크기로 반환. 따라서 파일의 크기를 byte로 표시하거나 파일에 몇
개의 block이 저장되어 있는가를 계산할 때 다음과 같이 사용
block 단위의 검색, 수정, 삭제
검색이란 목적에 따라 필요한 데이터들을 찾아내는 것을 말한다.
검색하고자 하는 이름을 입력받아 배열에 저장된 데이터와 비교해야 한다.
이때 이름은 문자열로 처리되므로 문자열 비교 함수인 strcmp 또는 strncmp를
사용할 수 있다.
파일 포인터를 원하는 block의 위치로 이동시킬 때 함수 fseek을 사용한다.
함수 ftell은 파일의 크기나 파일에 저장된 전체 block의 개수를 계산하는데
사용한다.
데이터를 삭제하는 방법은 삭제할 데이터가 위치한 곳을 공백으로 남겨두는
것이 아니라 삭제할 위치에 다른 데이터를 대체해 넣는 것이다.
따라서 삭제할 block의 수만큼 전체 block의 개수가 줄어들도록 처리해야
한다.