C 파일 입출력 완벽 가이드: 열기, 읽기, 쓰기, 위치 제어, 바이너리 처리
파일 I/O는 데이터를 영구 저장하고 불러오는 핵심 기능입니다. C 표준 라이브러리의 FILE* 스트림 기반 고수준 함수와 주요 패턴을 실무 중심으로 정리합니다.
파일 열기: fopen
FILE *fopen(const char *pathname, const char *mode);
모드 문자열 상세
| 모드 | 읽기 | 쓰기 | 생성 | 잘림 | 위치 | 바이너리 |
r | O | X | X | X | 시작 | rb |
w | X | O | O | O | 시작 | wb |
a | X | O | O | X | 끝 | ab |
r+ | O | O | X | X | 시작 | rb+, r+b |
| w+ | O | O | O | O | 시작 | wb+, w+b |
a+ | O | O | O | X | 끝 | ab+, a+b |
팁: 텍스트 모드에서 윈도우는 \n ↔ \r\n 변환, 바이너리 모드(b)는 변환 없음.
파일 닫기: fclose
int fclose(FILE *stream);
텍스트 파일 읽기/쓰기
문자 단위
int fgetc(FILE *stream); // 문자 읽기, EOF(-1) 반환 가능
int fputc(int c, FILE *stream); // 문자 쓰기
행 단위 (권장)
char *fgets(char *buf, int n, FILE *stream); // n-1자 또는 개행까지
int fputs(const char *s, FILE *stream); // 문자열 쓰기 (개행 안 함)
포맷 단위
int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
예제: 설정 파일 파싱
// config.txt
// host=localhost
// port=8080
// debug=true
FILE *fp = fopen("config.txt", "r");
char line[256];
char key[64], value[128];
while (fgets(line, sizeof(line), fp)) {
if (line[0] == '#' || line[0] == '\n') continue; // 주석/빈줄 스킵
if (sscanf(line, "%63[^=]=%127[^\n]", key, value) == 2) {
printf("설정: %s = %s\n", key, value);
}
}
fclose(fp);
바이너리 파일 읽기/쓰기
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
예제: 구조체 배열 저장/로드
#define MAX_RECORDS 1000
struct Record {
int id;
char name[32];
double score;
};
int save_records(const char *path, struct Record *recs, int count) {
FILE *fp = fopen(path, "wb");
if (!fp) return -1;
size_t written = fwrite(recs, sizeof(struct Record), count, fp);
fclose(fp);
return (written == count) ? 0 : -1;
}
int load_records(const char *path, struct Record *recs, int max_count) {
FILE *fp = fopen(path, "rb");
if (!fp) return -1;
size_t read = fread(recs, sizeof(struct Record), max_count, fp);
fclose(fp);
return (int)read;
}
파일 위치 제어 (Random Access)
| 함수 | 원형 | 설명 |
ftell | long ftell(FILE *stream) | 현재 위치 반환 (바이트 오프셋) |
fseek | int fseek(FILE *stream, long offset, int whence) | 위치 이동 |
rewind | void rewind(FILE *stream) | 시작으로 이동 + 에러 클리어 |
fgetpos | int fgetpos(FILE *stream, fpos_t *pos) | 이식성 좋은 위치 저장 |
fsetpos | int fsetpos(FILE *stream, const fpos_t *pos) | 저장된 위치로 복원 |
fseek 기준점 (whence)
SEEK_SET (0): 파일 시작부터
SEEK_CUR (1): 현재 위치부터
SEEK_END (2): 파일 끝부터
예제: 파일 크기 구하기
long file_size(FILE *fp) {
long cur = ftell(fp);
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, cur, SEEK_SET);
return size;
}
// 또는 (C11)
#include <stdio.h>
long size = 0;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
예제: 고정 레코드 랜덤 액세스
struct Record read_record(FILE *fp, long index) {
struct Record rec;
fseek(fp, index * sizeof(struct Record), SEEK_SET);
fread(&rec, sizeof(rec), 1, fp);
return rec;
}
에러 처리와 상태 확인
| 함수/매크로 | 용도 |
ferror(fp) | 에러 플래그 확인 (0 아님 = 에러) |
feof(fp) | EOF 플래그 확인 (읽기 시도 후 EOF 도달 시 설정) |
clearerr(fp) | 에러/EOF 플래그 초기화 |
perror(msg) | errno 기반 에러 메시지 출력 |
올바른 EOF 검사 패턴
// 잘못: feof()로 루프 제어
while (!feof(fp)) { // 마지막 읽기 후 feof 설정 전 루프 한 번 더 돔
fgets(buf, sizeof(buf), fp);
}
// 올바름: 읽기 함수 반환값으로 제어
while (fgets(buf, sizeof(buf), fp)) {
// 처리
}
if (ferror(fp)) {
perror("읽기 오류");
}
임시 파일
FILE *tmp = tmpfile(); // 자동 삭제되는 임시 파일 (wb+ 모드)
char tmpl[] = "/tmp/myprefixXXXXXX";
int fd = mkstemp(tmpl); // 안전한 임시 파일 생성 (POSIX)
FILE *fp = fdopen(fd, "w+b");
버퍼링 제어
void setbuf(FILE *stream, char *buf); // 버퍼 지정 (NULL=무버퍼)
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
// mode: _IOFBF(완전버퍼), _IOLBF(줄버퍼), _IONBF(무버퍼)
모범 사례 체크리스트
✅ fopen 반환값 항상 검사
✅ 텍스트/바이너리 모드 정확히 지정 (특히 윈도우)
✅ fgets + sscanf로 안전한 라인 파싱
✅ fread/fwrite 반환값으로 부분 I/O 감지
✅ fseek 오프셋 계산 시 sizeof 사용, 타입 크기 변경 대비
✅ 대용량 파일: fseeko/ftello (64비트 오프셋, POSIX) 또는 _fseeki64 (Windows)
✅ 에러 시 perror 또는 strerror(errno)로 상세 메시지
✅ 모든 경로에서 fclose 보장 (goto cleanup 패턴 또는 RAII 스타일)
C 언어
-
C 입출력(I/O) 마스터: scanf()와 printf() 완전 정복
-
C 파일 입출력: fopen, fprintf, fread, fseek 마스터하기
-
Python 파일 입출력: 파일 연산, 읽기, 쓰기, 관리 마스터하기
-
Axiomtek IPS960-511-PoE: 산업용 검사를 위한 올인원 러기드 비전 컨트롤러
-
아씨드(acceed) EDAM-4200 시리즈: 확장 가능하고 신뢰성 높은 데이터 통신을 위한 통합 I/O 모듈
-
C 함수 마스터: 선언, 정의, 호출, 인자 전달(값/참조), 재귀
-
C 헤더 파일 이해: 유형, 사용법, 모범 사례
-
I/O 카드 설명: 작동 원리와 중요성
-
MATLAB 데이터 내보내기: 파일 형식과 기법 총정리
-
C# 파일 입출력 마스터하기: 스트림, 읽기/쓰기, 고급 파일 작업