파일 입·출력


 파일에 대한 개념은 잘 알고계실겁니다. 응용 프로그램 부터 시작해서 텍스트파일 엑셀파일 등 모든 파일이 파일에 속합니다. 지금까지 앞에서 공부했던 내용들만 가지고 프로그램을 짜보면 한번 실행하면 다시 또 처음부터 실행해야됩니다. 파일 입·출력을 이용하면 파일을 이용해서 입력을받거나, 프로그램에서 입력한 내용을 파일로 출력을 할 수 있습니다. 파일 입·출력은 <stdio.h>헤더파일을 인클루드 하면 사용할 수 있습니다.


 우선, 파일 입·출력 공부에 앞서 비쥬얼 스튜디오의 프로젝트 경로를 쉽게 확인할 수 있는 방법을 알려드리겠습니다. 파일의 입력, 출력을 하기위해서는 소스코드가 생성되는 프로젝트 경로를 알고 있어야합니다. 아래 그림처럼 프로젝트를 우클릭하고 "파일 탐색기에서 폴더 열기"를 누르면 소스코드가 있는 프로젝트의 경로가 열립니다.



파일 입력

 파일 입력은 파일 열기, 작업, 파일 닫기 세 단계로 구성됩니다. 파일 열기는 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"입니다.

----------------------------------------------------------------------------------------

#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); // 메모리반환

}

----------------------------------------------------------------------------------------

 위 코드를 실행하면 도스창에는 아무런 문자열도 출력되지 않습니다.

 "data.txt"파일을 열어보면 아래 그림과 같이 1과 3.14가 아닌 깨진 문자들이 출력이 됩니다. 잘못 저장된걸까요?


 위에 저장된 "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




'언어 > C' 카테고리의 다른 글

VSCODE 환경 C개발 환경  (0) 2019.03.27
[C] 계좌 관리 프로그램  (2) 2017.01.10
[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27

+ Recent posts