C 언어 파일 입출력
C에서는 파일을 다루기 위해서는 운영체제가 제공하는 함수를 사용하거나 파일 스트림을 직접 읽고 쓰는 방식으로 구현해야 한다
파일 입출력 과정은 다음의 3단계로 이루어진다
- 파일을 연다 (파일 스트림 가져옴)
- 파일을 읽거나 사용한다 (파일 스트림 사용)
- 파일을 닫는다 (리소스 정리)
파일 열기
파일을 열기 위해 fopen을 사용한다
FILE* fopen(const char* filename, const char* mode);
- filename: 열고자 하는 파일 이름 (경로 포함 가능)
- mode: 파일을 열 때 사용할 모드 (읽기, 쓰기, 추가 등)
- 반환값: 파일 스트림 포인터 (FILE*), 실패 시 NULL 반환
파일 열기 모드는 다음의 종류들이 있다
모드 | 설명 |
"r" | 읽기 전용 (파일이 존재해야 함) |
"w" | 쓰기 전용 (파일이 존재하면 기존 파일의 모든 내용 삭제 후 진행됨) |
"a" | 추가 모드 (파일이 존재하면 끝에 추가) |
"r+" | 읽기 / 쓰기 모드 (파일이 존재해야 함) |
"w+" | 읽기 / 쓰기 모드 (파일이 존재하면 기존 파일의 모든 내용 삭제 후 진행됨) |
"a+" | 읽기 / 추가 모드 (파일이 존재하면 끝에 추가) |
#include <stdio.h>
#define FILE_NAME "example.txt"
int main(void)
{
FILE* file;
/* 1. "w" 모드: 파일 쓰기 (기존 내용 삭제) */
file = fopen(FILE_NAME, "w");
if (file == NULL) {
perror("파일 열기 실패");
return 1;
}
fprintf(file, "첫 번째 줄: 파일을 새로 씀\n");
fclose(file);
printf("\n[쓰기 모드 \"w\"] 기존 내용을 지우고 새로 작성 완료!\n");
/* 2. "a" 모드: 파일 끝에 추가 */
file = fopen(FILE_NAME, "a");
if (file == NULL) {
perror("파일 열기 실패");
return 1;
}
fprintf(file, "두 번째 줄: 파일에 내용 추가됨\n");
fclose(file);
printf("\n[추가 모드 \"a\"] 기존 내용을 유지하면서 새로운 내용 추가 완료!\n");
/* 3. "r" 모드: 파일 읽기 */
file = fopen(FILE_NAME, "r");
if (file == NULL) {
perror("파일 열기 실패");
return 1;
}
printf("\n[읽기 모드 \"r\"] 파일 내용 출력:\n");
char ch;
while ((ch = fgetc(file)) != EOF) {
putchar(ch);
}
fclose(file);
return 0;
}
================ 실행 결과 ================
[쓰기 모드 "w"] 기존 내용을 지우고 새로 작성 완료!
[추가 모드 "a"] 기존 내용을 유지하면서 새로운 내용 추가 완료!
[읽기 모드 "r"] 파일 내용 출력:
첫 번째 줄: 파일을 새로 씀
두 번째 줄: 파일에 내용 추가됨
또한 각 명령어의 뒤에 b를 붙이면 이진 파일 모드로 사용할 수 있다
Unix/Linux/macOS에서는 텍스트 모드와 차이가 없지만, Windows에서는 개행 문자 처리를 다르게 한다
파일 사용하기
파일을 연 후에는 데이터를 읽거나 쓸 수 있다. C에서는 파일을 다룰 때 표준 입출력 라이브러리를 사용하여 다양한 방법으로 데이털르 처리할 수 있다
파일을 사용할 때는 다음과 같은 중요 함수를 사용한다
함수 | 설명 |
fgetc(FILE* stream) | 파일에서 한 문자를 읽는다 |
fgets(char* str, int count, FILE* stream) | 파일에서 한 줄을 읽는다 (개행 문자 포함) |
fscanf(FILE* stream, const char* format, ...) | 서식 지정 문자열을 이용하여 데이터를 읽는다 |
fputc(int c, FILE* stream) | 파일에 한 문자를 쓴다 |
fputs(const char* str, FILE* stream) | 문자열을 파일에 쓴다 |
fprintf(FILE* stream, const char* format, ...) | 서식 지정 문자열을 이용하여 데이터를 쓴다 |
#include <stdio.h>
#define FILE_NAME "data.txt"
int main(void)
{
FILE* file;
/* 1. 파일에 데이터 쓰기 */
file = fopen(FILE_NAME, "w");
if (file == NULL) {
perror("파일 열기 실패");
return 1;
}
fprintf(file, "C 파일 입출력 예제\n");
fprintf(file, "두 번째 줄: 파일 쓰기 완료!\n");
fclose(file);
printf("\n[쓰기 완료] 파일에 데이터 저장 완료!\n");
/* 2. 파일에서 한 줄씩 읽기 */
file = fopen(FILE_NAME, "r");
if (file == NULL) {
perror("파일 열기 실패");
return 1;
}
printf("\n[읽기 시작] 파일 내용:\n");
char buffer[100];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer); /* 개행 문자 포함 출력 */
}
fclose(file);
return 0;
}
================ 실행 결과 ================
[쓰기 완료] 파일에 데이터 저장 완료!
[읽기 시작] 파일 내용:
C 파일 입출력 예제
두 번째 줄: 파일 쓰기 완료!
파일 닫기
파일을 사용한 후에는 반드시 fclose를 사용하여 파일을 닫아야 한다. 닫지 않으면 문제가 발생할 수 있다
운영체제에서 동시에 열 수 있는 파일 개수에는 제한이 있어, 일정 개수 이상에서 파일 열기를 실패하여 널 포인터를 반환한다. 또한 Windows에서 열려 있는 파일을 다른 파일이 수정할 수 없게 제한을 것처럼 사용에 제약이 걸리는 경우도 있기 때문이다
#include <stdio.h>
#define MAX_FILES 100000 /* 운영체제에 따라 허용 개수가 다름 */
int main(void)
{
FILE* files[MAX_FILES];
int i;
for (i = 0; i < MAX_FILES; i++) {
files[i] = fopen("test_file.txt", "w");
if (files[i] == NULL) {
perror("파일 열기 실패! 너무 많은 파일을 열었습니다.");
break;
}
fprintf(files[i], "파일 핸들 개수 테스트 중\n");
}
printf("\n총 %d개의 파일을 열었습니다.\n", i);
/* 파일 닫기 (누수 방지) */
for (int j = 0; j < i; j++) {
fclose(files[j]);
}
return 0;
}
================ 실행 결과 ================
파일 열기 실패! 너무 많은 파일을 열었습니다.: Too many open files
총 32765개의 파일을 열었습니다.
특정 개수를 넘으면 오류 메시지를 출력하는 것을 확인할 수 있었다. 항상 자원을 사용하면(fopen) 정리(fclose)하는 것을 습관화 하자
Reference
fopen, fopen_s - cppreference.com
fgetc, getc - cppreference.com
printf, fprintf, sprintf, snprintf, printf_s, fprintf_s, sprintf_s, snprintf_s - cppreference.com
scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s - cppreference.com