Jiyong's STUDY

fopen와 fclose 그리고 파일 스트림의 모드 본문

프로그래밍/C

fopen와 fclose 그리고 파일 스트림의 모드

Kingjiyong 2018. 5. 29. 02:40

파일 스트림과 관련된 함수 fopen, fclose


이전에 입출력 스트림에 대하여 다룬 적이 있다.

일반적인 콘솔 입출력 스트림은 프로그램이 실행되면 생성되고, 종료되면 사라지게 된다.


하지만 파일 스트림은 사용자가 필요에 따라 생성을 요청할 수 있고, 닫을 수 있다. 즉 수동이라는 의미이다.


fopen 함수와 fclose 함수를 소개하기 전에 먼저 파일 스트림의 모드를 설명하겠다.


파일 스트림의 모드란 무엇인가?


파일 스트림의 모드는 두글자 문자의 조합으로 이루어진다.

첫째는 입력을 하느냐 또는 출력을 하느냐 이고,

둘째는 텍스트 모드로 입출력을 하느냐 또는 바이너리 모드이냐 이다.


첫 번째로는 r은 출력, w는 입력, a는 덧붙여 입력이다.

출력을 할 때엔 전달한 파일의 이름과 일치하는 파일이 없다면 EOF를 출력한다.

하지만, 입력을 할 때에는 없다면 생성을 하기에 문제는 없다.

단, w는 처음부터 입력한다는 의미가 있다. 즉 원래 파일이 존재한다고 해도 처음부터 쓴다. 덮어쓰기를 한다는 의미이다.

그렇기에 덧붙여서 입력을 하기 위해는 a를 사용해야 한다. 마찬가지로 파일이 없으면 처음부터.


또한, r+ w+ a+와 같은 모드도 존재한다. 이는 입출력이 모두 가능한 스트림이다.

하지만 스트림은 단어 그대로 강과 같다. 한쪽으로만 흐르는 강처럼 스트림도 한쪽으로만 흐른다.

그렇다면 하나의 스트림으로 입출력을 동시에 하는 것은 그 질서를 깨트리는 일이다.

사실 그러한 방법으로 입출력을 할 수는 있으나 복잡하다. 차라리 두개의 스트림을 사용하는게 더 편하며 안정적이므로 사용하지 말자.


두 번째로 t는 텍스트 모드, b는 바이너리 모드이다.

텍스트와 바이너리를 구분하자면, 텍스트는 말 그대로 텍스트이다.

우리가 직관적으로 볼 수 있는 파일.

하지만 바이너리는 다르다. 우리가 직관적으로 편집기를 열어 볼 수 없고 그에 따른 프로그램으로 확인을 해야 하는 파일을 말한다.

예를 들자면 mp3, mp4와 같은 음원과 영상 또한 jpg, psd처럼 포토샵 파일이나 사진처럼 연결된 프로그램으로 확인해야 하는 파일.


사실 조금 더 직관적으로 텍스트 모드와 바이너리 모드를 구분할 수 있다.

텍스트 모드는 우리가 입력하고 읽을 수 있어야 한다. 예를 들자면 줄 개행이 이루어져야 제대로 볼 수 있지 않을까?


예를 들자면 내가 


This is

Text mode


라는 텍스트를 입력 후 출력하고자 한다.

그렇다면 C언어에서는 어떻게 입력을 해야 저렇게 출력이 될까?

This is\nText mode처럼 줄 개행 문자가 입력이 되어야 저렇게 출력이 된다.


여기서 궁금증이 생길 수 있다.

바이너리 모드도 저렇게 입력을 하면 결국 같은 입력 결과가 나오지 않을 것인가 하는 생각이 들 수 있다.


하지만 사실 조금 다르다.


운영체제마다 줄 개행을 위한 문자는 다르다.

윈도우의 경우엔 \r\n이 줄 개행을 의미한다.

리눅스의 경우엔 c와 마찬가지. \n이다.

Mac의 경우엔 \r이다.


그래서 존재하는 것이 텍스트 모드이다. \n을 각 운영체제의 줄 개행 문자로 변경해야 하기 때문이다.


#include <stdio.h>

FILE* fopen(const char* filename, const char* mode);


fopen은 두 가지의 매개변수를 요한다.

첫 번째 매개변수는 filename. 즉 사용자가 요청할 스트림의 파일의 이름이다.

두 번째 매개변수는 사용자가 요청할 스트림의 모드이다.

 

파일 스트림을 여는 예시를 보이자면,


FILE *fp=NULL;

fp=fopen("test.txt", "wt");


이렇게 test.txt 라는 파일을 write하기 위한 텍스트 모드로 파일 스트림을 열었다.


여기서 보면 또 의문이 생긴다.

FILE형 포인터? 그게 무엇인가? 지금까지 FILE이라는 자료형은 들어본 적이 없다.


FILE은 구조체이다. 파일 스트림과 관련된 정보를 저장하기 위한 구조체이다.


위 예제는 FILE형 포인터를 선언하고 fopen 함수로 요청한 스트림을 가리키게 한 것이라고 생각하는 게 쉽다.

그러면 그 포인터의 이름 fp는 test.txt를 가리키는 지시자가 된다.

fp를 통해서 test.txt에 접근을 할 수 있게 된 셈이다.


여기서 만약 파일을 여는 것에 실패를 했다면 foepn 함수는 스트림이 아니라 0. 즉 널 값이 리턴된다.


#include <stdio.h>

FILE *fclose(FILE *stream);


파일 스트림을 여는 fopen 함수가 있다면, 그 스트림을 닫는, 즉 파일을 닫는 함수는 fclose다.

fclose 함수를 선언하면 그 즉시 그 파일과 관련된 스트림은 닫히며 관련된 리소스는 소멸된다.

또한 출력버퍼를 비우는 기능이 있다.


사실 fclose를 사용하지 않아도 프로그램이 종료되면 생성되었던 모든 스트림은 닫히며 출력버퍼는 비워진다.

그렇다면 왜 fclose를 사용하는가? 하는 의문이 생길 수 있다.


첫 번째는 불필요한 리소스를 소멸시키기 위함이다. 사용되지 않는 메모리가 계속 존재한다면 손해가 아닌가.

두 번째는 출력버퍼를 비우기 위해서이다. 사실 이 부분이 가장 중요하다고 보면 된다.


fputs나 fputc와 같은 함수로 출력을 했을 때, 그 문자나 문자열은 바로 파일로 이동하는게 아니다.

이전에도 언급했지만 그 정보가 출력버퍼로 이동되는 순간 함수는 반환된다. 파일으로 정보가 넘어가는 건 버퍼의 몫이다.


자 그렇다면 만약 중요한 정보를 입력 받아 그 정보를 파일에 출력하려고 한다.

만약, 입력을 받고 출력버퍼로 이동 된 후, 파일에 전송되기 이전에 어떠한 이유라도 프로그램이 종료된다면 어떤 일이 일어날까?

그 중요한 정보는 손실된다.


그렇다면 우리는 파일 스트림을 필요할 때 열고 닫는 습관을 가져야 그러한 손실을 방지할 수 있다.

리소스의 이득은 덤이다.