본문 바로가기
Programming/C++

FILE 구조체의 포인터

by OKOK 2017. 7. 24.

FILE 구조체의 포인터


이 함수는 전달된 인자를 참조해서 사용자가 요구하는 파일을 원하는 방식으로 개방시켜 주는 함수이다. 지정한 파일과의 데이터 입력, 출력을 위해 스트림을 생성하는 함수이다. 즉, 파일의 개방이나 스트림의 생성은 같은 의미를 지닌다는 뜻이다.


리텁 값은 무엇일까? 리턴 값은 FILE 이라는 구조체 변수의 포인터이다. 여기서 FILE 구조체가 어떻게 생겼는지 알 필요는 없다. 왜냐하면 FILE 구조체 변수의 멤버를 우리가 직접 조작하는 일은 없기 때문이다. 다만, FILE 구조체 변수가 어떠한 정보를 지니는지 정도만 알면 된다. 결론부터 이야기하면, FILE 구조체 변수는 개방한 파일에 대한 여러 가지 정보를 지니는 변수이다. 


무슨 목적으로 사용하게 되는가? 데이터를 입력 출력 할때, FILE 구조체 변수를 참조하면 데이터를 입출력할 파일이 무엇인지 알 수 있다. 위치 정보를 참조할 때, FILE 구조체 변수는 파일 내의 위치 정보를 지니고 있다. 이를 참조하면, 해당 파일의 어느 위치까지 데이터를 입력 혹은 출력했는지 알 수 있다. 파일의 끝을 확인 할 때, FILE 구조체 변수를 참조하면 파일의 끝까지 데이터를 읽어 들였는지에 대한 정보를 알 수 있다.



파일의 종결


프로그램이 종료되면 개방한 파일도 자동적으로 종결된다. 이 말은 프로그램이 종료되면 생성되었던 스트림도 자동적으로 소멸된다는 뜻과 같다. 그러나 개방한 파일은 다 쓰고 나면(데이터 입출력이 완료되면) 반드시 프로그램상에서 닫아줘야 한다. 프로그램이 종료되면 자동적으로 닫히는 파일을 프로그램상에서 직접 닫아줘야 하는 이유는 무엇일까? 지금까지 작업한 내용이 시스템의 오류에 의해서 지워져 버리는 문제를 막기 위해서이다. 프로그램이 종료되기 전에 예측치 못한 오류가 발생하면 데이터의 손실이 발생할 수 있다. 그래서 프로그램상에서 파일을 개방한 후에 파일의 사용이 끝나면 바로 닫아주는 것이다. 이것이 좋은 습관이다. 파일을 닫아주지 않은 상태에서 프로그램에 문제가 생긴다면 파일이 어떻게 될지는 아무도 예측 못하게 된다. 


#pragma warning(disable:4996)


#include <stdio.h>


int main(void)

{

int state;


FILE * file = fopen("Test.txt", "wt");

if (file == NULL) {

printf("file open error!\n");

return 1;

}


state = fclose(file);

if(state != 0) {

printf("file close error!\n");

return 1;

}


return 0;


예제는 파일의 개방과 종결ㅇㄹ 보여주었다. 앞으로 보게 될 파일 입출력 프로그램에서 빠지지 않고 드앙하게 되며, 개방과 종결 사이에 데이터를 입출력하는 코드만 삽입하면 우리가 원하는 거의 대부분의 파일 조작이 가능해진다. 그렇다면 다음 포스팅부터 데이터를 입출력 할 때 사용하는 함수들을 공부해 보도록 합니다. 



fputs 함수를 이용한 파일 출력


#pragma warning(disable:4996)


#include <stdio.h>


int main(void)

{

int state;


FILE * file = fopen("Test.txt", "wt");

if (file == NULL) {

printf("file open error!\n");

return 1;

}


puts("Don't Worry~");

fputs("Don't Worry~\n", stdout);

fputs("Don't Worry~\n", file);


state = fclose(file);

if (state != 0) {

printf("file close error!\n");

return 1;

}


return 0;


이 출력 결과는 위의 2개의 줄에 의한 것이다. 그렇다면 3번쨰 줄에 의한 결과는 어떻게 확인 할 수 있을까? 현재 Test.txt 라는파일이 디렉토리에 생성 되었을 것이다. 메모장이나 이와 비슷한 편집기를 사용하여 열어보도록 합니다. 문자열이 저장되었음을 확인 할 수 있습니다. 



fgets 함수를 이용한 파일 입력

#include <stdio.h>


int main(void)

{

int state;

char buf[30];


FILE * file = fopen("Test.txt", "rt");

if (file == NULL) {

printf("file open error!\n");

return 1;

}


fputs("data input: ", stdout);

fgets(buf, sizeof(buf), stdin);

puts(buf);


fgets(buf, sizeof(buf), file);

puts(buf);


state = fclose(file);

if (state != 0) {

printf("file close error!\n");

return 1;

}


return 0;


fgets 함수를 호출하고 있습니다. 따라서 입력 스트림을 지정할 수 있는데, 세 번째 인자로 stdin을 전달하였으므로 키보드로부터 데이터를 입력받을 것입니다. 그 아래 줄에서도 fgets 함수를 호출하고 있습니다. 이번에는 입력 스트림을 10번째 줄에서 읽기 전용 모드로 개방한 파일로 지정해 주고 있습니다. 따라서 Text.txt 파일 내에 존재하는 문자열을 읽어들이게 됩니다. 



#include<stdio.h>


int main(void)

{

int state;

int i, j;

int a = 0, b = 0, c = 0;

char c1 = 0, c2 = 0;


FILE * file = fopen("Test.txt", "wt");

if (file == NULL) {

printf("file open error!\n");

return 1;

}


for (i = 2; i < 10; i++)

for (j = 1; j < 10; j++)

fprintf(file, "%d * %d = %d\n", i, j, i*j);


state = fclose(file);

if (state!= 0) {

printf("file close error!\n");

return 1;

}


file = fopen("Test.txt", "rt");

if (file == NULL) {

printf("file open error!\n");

return 1;

}


for(i=2; i<10; i++)

for (j = 1; j < 10; j++)

{

fscanf(file, "%d %c %d %c %d", &a, &c1, &b, &c2, &c);

printf("%d %c %d %c %d\n", a, c1, b, c2, c);

}


state = fclose(file);


return 0;


파일에 문자열을 저장하고 있음을 볼 수 있습니다. fputs 함수와 달리 저장할 문자열의 형식을 지정해주고 있습니다. 파일에 저장된 문자열을 형식을 지정하여 읽고 있습니다. 출력 결과를 통해서도 확인이 가능하고, 생성된 파일을 메모장과 같은 편집기를 이용해서 열어봐도 확인이 가능합니다. 


그렇다면 이것을 활용하여 센서로 부터 나오는 데이터들을 txt 파일로 저장할 수 있지 않을까?



파일 입출력 함수와 FILE 구조체 변수

임의의 파일을 하나 개방하고, 데이터를 읽어들이기 위한 함수를 여러 번 호출하면 신기하게도 이전에 읽어들인 부분의 뒤를 이어서 데이터를 읽어들인다. 즉 순차적으로 데이터를 읽어들이는 것이다. 이러한 일이 가능하다는 것은 파일을 어디까지 읽었는지, 혹은 어디까지 썼는지, 그위치를 기억하고 있다는 뜻이다. 파일을 개방하는 경우 이에 대한 FILE 구조체 변수의 포인터가 리턴되고, 그 포인터가 가리키는 구조체 변수 내에는 파일 위치 지시자에 해당하는 변수가 존재한다. 이 변수는 파일 내의 위치 정보를 지니고 있으며, 이 변수의 값은 파일에서부터 데이터를 읽거나 쓰는 경우 변경된다.