파일 입·출력
파일에 대한 개념은 잘 알고계실겁니다. 응용 프로그램 부터 시작해서 텍스트파일 엑셀파일 등 모든 파일이 파일에 속합니다. 지금까지 앞에서 공부했던 내용들만 가지고 프로그램을 짜보면 한번 실행하면 다시 또 처음부터 실행해야됩니다. 파일 입·출력을 이용하면 파일을 이용해서 입력을받거나, 프로그램에서 입력한 내용을 파일로 출력을 할 수 있습니다. 파일 입·출력은 <stdio.h>헤더파일을 인클루드 하면 사용할 수 있습니다.
우선, 파일 입·출력 공부에 앞서 비쥬얼 스튜디오의 프로젝트 경로를 쉽게 확인할 수 있는 방법을 알려드리겠습니다. 파일의 입력, 출력을 하기위해서는 소스코드가 생성되는 프로젝트 경로를 알고 있어야합니다. 아래 그림처럼 프로젝트를 우클릭하고 "파일 탐색기에서 폴더 열기"를 누르면 소스코드가 있는 프로젝트의 경로가 열립니다.
![](https://t1.daumcdn.net/cfile/tistory/26700342586E605C23)
파일 입력
파일 입력은 파일 열기, 작업, 파일 닫기 세 단계로 구성됩니다. 파일 열기는 fopen()함수, 파일에서 값을 불러올때는 fscanf()함수 파일을 닫을때는 fclose()함수를 사용합니다. 파일을 열고나서 닫지 않으면, 다른 곳에서 해당파일에 접근할 수 가 없으므로 꼭 사용한 후에는 닫아줘야 합니다. 파일 입·출력에서는 파일 포인터를 사용합니다. 파일 포인터는 타입이 파일인 포인터 라고 생각하시면 됩니다.
- fopen()함수
파일을 열 때 사용하는 함수입니다. 열 파일이 존재하지 않거나, 실패할 경우 NULL값을 반환합니다.
----------------------------------------------------------------------------------------
fopen(파일이름, 파일모드); // 파일모드 r(read)=읽기 w(write)=쓰기(파일 출력에 사용)
FILE *fp; // 파일포인터 선언
fp=fopen("test.txt","r"); // test.txt 파일을 읽기
----------------------------------------------------------------------------------------
- fscanf()함수
fscanf()함수는 파일의 내용을 읽어올 때 사용하는 함수로, 파일 포인터를 인자값으로 사용한다는 점 외에는 scanf()함수와 유사합니다.
----------------------------------------------------------------------------------------
fscanf(파일 포인터, 포맷 문자열, 값1, 값2 ...);
FILE *fp; // 파일포인터 선언
int i;
fscanf(fp,"%d",&i);
----------------------------------------------------------------------------------------
- fclose()함수
fclose()함수는 파일을 닫는 함수로, 열려있는 파일 포인터를 인수로 넘겨주면 파일을 닫는 역할을 합니다.
----------------------------------------------------------------------------------------
fclose(파일 포인터);
FILE *fp; // 파일포인터 선언
fclose(fp);
----------------------------------------------------------------------------------------
위 세 함수를 이용해서 "data.txt"라는 파일에 정수를 입력해서, "data.txt"파일을 입력 받고 정수를 출력하는 코드를 작성해 봤습니다. 이 때 "data.txt"처럼 사용 할 파일은 소스파일과 같은 경로에 있어야 합니다. 아래 그림은 "data.txt"입니다.
![](https://t1.daumcdn.net/cfile/tistory/26714444586E5FEA22)
----------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
int main()
{
int a,b; // 파일에서 읽어올 때 fscanf에 사용할 변수a와 반복문에 사용할 변수 b 선언
int *data; // 동적메모리에 사용할 정수형 포인터 선언
FILE *fp; // 파일포인터 fp 선언
fp = fopen("data.txt","r"); // "data.txt"파일 열기
if (fp != NULL) // 파일이 정상적으로 열렸을 때 if문실행
{
fscanf(fp,"%d",&a); // "data.txt"파일의 첫번째 값을 입력받아서
data = (int *)malloc(sizeof(int)*a); // 첫번째 값만큼 동적으로 정수형 배열을 만듭니다.
for (b = 0; b < a; b++) // 배열의 크기만큼 값을 입력 받음
{
fscanf(fp, "%d", &data[b]);
}
fclose(fp); // 입력을 받은뒤에 파일닫기
for (b = 0; b < a; b++) // 입력받은 배열을 출력
{
printf("data[%d] : %d \n", b, data[b]);
}
free(data); // 메모리 반환
} //close if()
else{
printf("파일 입력받기 실패 \n");
}
}
----------------------------------------------------------------------------------------
위 코드를 실행한 결과입니다. "data.txt"의 처음 값은 배열의 크기가 되고, 나머지 값들은 순차적으로 배열에 저장해서 출력했습니다.
파일 출력
파일 출력은 두 가지로 나뉩니다. 기존 파일을 사용해서 출력하는 방법과 새로운 파일을 만들어서 출력하는 방법이 있습니다. 두 방법은 기존의 파일을 이용하는 점과 새로만든다는 점만 다를뿐 구현방법은 동일합니다. 파일 출력은 파일 입력과 동일하게 fopen()함수를 사용합니다. fscanf()함수와 반대로 fprintf()함수를 이용해 파일에 출력합니다.
- fopen()함수
fopen()함수의 파일모드에는 r(read),w(write)외에도 a(append)가있습니다.
----------------------------------------------------------------------------------------
fopen()함수의 파일모드
- w = 해당 파일이 없으면 파일을 생성, 해당 파일이 있으면 내용을 덮어쓰기
- a = 해당 파일이 없으면 파일을 생성, 해당 파일이 있으면 파일의 끝부터 내용 추가
----------------------------------------------------------------------------------------
- fprintf()함수
fprintf()함수는 파일에 문자열을 출력하는 함수로 파일 포인터를 인자값으로 사용한다는 점 외에는 printf()함수와 유사합니다.
----------------------------------------------------------------------------------------
FILE *fp;
fprintf(fp,"문자열 : %s \n",text);
----------------------------------------------------------------------------------------
문자열이 아닌 자료형 등의 데이터를 읽고 쓰려면 어떻게 해야될까요? 이때는 2진수(binary)값을 직접 읽고 씁니다. fopen()함수의 기존 파일모드에 b를 붙여서 사용합니다. 바이너리 값을 읽고 쓸때에는 fread()함수와 fwrite()함수를 사용합니다.
----------------------------------------------------------------------------------------
fopen(“data.txt”, “rb”);
fopen(“data.txt”, “wb”);
size_t fread( void *ptr, size_t size, size_t nitems, FILE *stream);
(파일에서 읽은 값을 저장할 포인터, 자료형의 크기, 자료형의 개수, 파일 포인터)
size_t fwrite( void *ptr, size_t size, size_t nitems, FILE *stream);
사용 방법은 동일하지만, 변수 포인터에 들어있는 값을 파일에 쓴다는점이 다릅니다.
----------------------------------------------------------------------------------------
아래 코드는 바이너리 값으로 구조체를 파일로 저장하고 읽어오는 코드입니다.
----------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
struct Node{
int a;
double b;
};
int main()
{
struct Node *print;
FILE *fp;
fp = fopen("data.txt", "wb"); // 바이너리값으로 저장
print = (struct Node*)malloc(sizeof(struct Node));
print->a = 1;
print->b = 3.14;
fwrite((void*)print, sizeof(struct Node), 1, fp);
fclose(fp); // 파일 닫기
free(print); // 메모리반환
}
----------------------------------------------------------------------------------------
위 코드를 실행하면 도스창에는 아무런 문자열도 출력되지 않습니다.
![](https://t1.daumcdn.net/cfile/tistory/216AAB41586E6B7134)
"data.txt"파일을 열어보면 아래 그림과 같이 1과 3.14가 아닌 깨진 문자들이 출력이 됩니다. 잘못 저장된걸까요?
![](https://t1.daumcdn.net/cfile/tistory/24047A42586E6BA13C)
위에 저장된 "data.tx"t파일을 읽어와서 출력하는 코드입니다.
----------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
struct Node{
int a;
double b;
};
int main()
{
struct Node *open;
FILE *fp;
fp = fopen("data.txt", "rb"); // 바이너리값으로 불러오기
open = (struct Node*)malloc(sizeof(struct Node));
fread((void*)open, sizeof(struct Node), 1, fp);
printf("open->a = %d \n", open->a);
printf("open->b = %.2lf \n", open->b);
fclose(fp); // 파일닫기
free(open); // 메모리반환
}
----------------------------------------------------------------------------------------
위 코드의 실행결과입니다. 파일을 출력했을때의 값이 정상적으로 출력되는걸 확인할 수 있습니다.
* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2
스타일 C프로그래밍 저.김종훈,김종진 출.WellBook