C 언어의 fopen() 함수는 지정된 경로의 파일을 열기 위해 사용하는 표준 입출력 라이브러리 함수입니다. 파일을 열 때 어떤 모드(mode)를 지정하느냐에 따라 기존 파일의 내용이 유지될 수도, 삭제될 수도 있으므로 각 모드의 동작 방식을 정확히 이해하는 것이 중요합니다.
fopen() 함수 문법
FILE *fopen(const char *filename, const char *mode);
fopen() 함수는 첫 번째 인자로 열고자 하는 파일의 이름(경로)을, 두 번째 인자로 파일을 여는 방식을 나타내는 모드 문자열을 받습니다. 사용할 수 있는 대표적인 모드는 다음과 같습니다.
- 'r' : 읽기 전용으로 파일을 엽니다.
- 'w' : 쓰기 전용으로 파일을 열며, 기존 내용이 있다면 모두 삭제됩니다.
- 'a' : 추가(append) 전용으로 파일을 열며, 파일 끝에 내용을 덧붙입니다.
- 'r+', 'w+', 'a+' : 읽기와 쓰기를 모두 허용하는 확장 모드입니다.
쓰기 모드('w')로 기존 파일을 열면 어떻게 될까?
쓰기 모드에서 fopen()의 동작은 해당 파일의 존재 여부에 따라 달라집니다.
- 열려는 파일이 현재 디렉터리에 존재하지 않으면, 비어 있는 새 파일이 생성됩니다.
- 파일이 이미 존재하는데 'w' 또는 'w+' 모드로 열면, 기존 내용이 모두 삭제된 후 새로운 데이터가 기록됩니다.
예제 1 – 'w' 모드로 파일 열기
다음 프로그램은 'w' 모드로 파일을 열고 문자열을 기록하는 예제입니다.
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *opFile = fopen("test.txt", "w");
if (opFile == NULL){
puts("Couldn't open file");
exit(0);
}
else{
fputs("includehelp", opFile);
puts("Write operation successful");
fclose(opFile);
}
return 0;
}
실행 결과
Write operation successful
코드 실행 전 파일의 내용이 C programming language였다면, 쓰기 연산 후에는 파일 내용이 includehelp로 완전히 교체됩니다. 즉, 'w' 모드는 쓰기 작업 자체는 정상적으로 수행하지만, 기존에 파일에 있던 내용을 모두 지워버린다는 점에 주의해야 합니다.
이러한 문제를 해결하기 위해 C 표준은 프로그램의 요구 사항에 따라 선택해 사용할 수 있는 두 가지 대안을 제공합니다.
- 'a'(append, 추가) 모드 : 새로운 내용을 파일의 기존 내용 끝에 덧붙여 기록합니다.
- 'wx' 모드 : 배타적 생성(exclusive create) 모드로, 같은 이름의 파일이 이미 존재하면 fopen()이 실패(NULL 반환)하여 기존 파일을 실수로 덮어쓰는 것을 방지합니다.
예제 2 – 'a' 모드로 기존 파일에 내용 추가하기
아래 프로그램은 'a' 모드를 사용해 기존 파일의 내용을 유지한 채 새로운 문자열을 추가하는 예제입니다.
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *opFile = fopen("test.txt", "a");
if (opFile == NULL){
puts("Couldn't open file");
exit(0);
}
else{
fputs("includehelp", opFile);
puts("Write operation successful");
fclose(opFile);
}
return 0;
}
실행 결과
Write operation successful
실행 전 파일 내용이 C programming language였다면, 'a' 모드로 쓰기 연산을 수행한 후 파일 내용은 C programming language includehelp가 됩니다. 기존 내용이 그대로 보존되고 새 문자열이 뒤에 추가된 것을 확인할 수 있습니다.
예제 3 – 'wx' 모드로 안전하게 파일 생성하기
'wx' 모드는 파일이 이미 존재하는 경우 열기에 실패하므로, 기존 파일을 보호하면서 새 파일만 생성하고 싶을 때 유용합니다.
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *opFile = fopen("test.txt", "wx");
if (opFile == NULL){
puts("Couldn't open file");
exit(0);
}
else{
fputs("includehelp", opFile);
puts("Write operation successful");
fclose(opFile);
}
return 0;
}
실행 결과
같은 이름의 파일이 이미 존재하면 fopen()이 NULL을 반환하므로 Couldn't open file이 출력됩니다. 반면 해당 파일이 없다면 새 파일이 생성되고 쓰기가 성공하여 Write operation successful이 출력됩니다.
모드별 동작 비교
| 모드 | 파일이 존재할 때 | 파일이 없을 때 |
|---|---|---|
| 'w' | 기존 내용 삭제 후 처음부터 기록 | 새 파일 생성 |
| 'a' | 기존 내용 유지, 파일 끝에 추가 | 새 파일 생성 |
| 'wx' | 열기 실패 (NULL 반환) | 새 파일 생성 후 기록 |
정리하면, 파일의 기존 내용을 보존하면서 데이터를 추가하려면 'a' 모드를, 기존 파일을 실수로 덮어쓰지 않도록 보호하려면 'wx' 모드를 사용하는 것이 좋습니다. 또한 fopen() 호출 후에는 반드시 반환값이 NULL인지 검사하고, 작업이 끝나면 fclose()로 파일을 닫는 습관을 들이면 안정적인 파일 입출력 코드를 작성할 수 있습니다.