파일 I/O는 함수 이름보다 열기 실패, 읽기 결과, 닫기 책임을 먼저 봐야 합니다.
fopen모드 문자열이 다시 헷갈린다- 텍스트 파일과 바이너리 파일을 어떻게 다르게 읽는지 정리하고 싶다
feof를 루프 조건으로 써도 되는지 확인하고 싶다
숏컷 코드
FILE *fp = fopen("notes.txt", "r");
if (fp == NULL) {
perror("fopen");
return 1;
}
/* read or write */
fclose(fp);문법
파일 I/O는 함수 이름을 많이 아는 것보다 열기 성공 여부, 읽기/쓰기 반환값, 닫기 책임을 놓치지 않는 쪽이 훨씬 중요합니다.
"r": 읽기"w": 새로 쓰기, 기존 내용 덮어씀"a": 뒤에 이어쓰기
그리고 바이너리면 b를 붙입니다.
"rb""wb"
텍스트와 바이너리를 섞어 생각하지 않는 것이 중요합니다.
텍스트 파일은 줄 단위가 기본 패턴에 가깝습니다.
char line[256];
while (fgets(line, sizeof(line), fp) != NULL) {
printf("%s", line);
}- 버퍼 크기를 넘지 않는다
- 개행 포함 여부를 눈으로 확인할 수 있다
- 루프 조건이 읽기 성공 여부와 바로 연결된다
while (!feof(fp)) 같은 패턴보다 훨씬 안전합니다.
확인 포인트
size_t nread = fread(buf, sizeof(buf[0]), count, fp);
if (nread < count && ferror(fp)) {
perror("fread");
}바이너리는 "원소 수" 기준으로 읽고 씁니다.
- 두 번째 인자: 원소 하나 크기
- 세 번째 인자: 원소 개수
- 반환값: 실제로 읽거나 쓴 원소 수
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);이 패턴은 파일 크기를 확인하거나 다시 처음부터 읽을 때 자주 씁니다.
다만 ftell 결과를 무조건 "유효한 전체 파일 크기"로 가정하기보다, 스트림 종류와 실패 여부를 같이 봐야 합니다.
체크포인트
fopen실패를 검사하지 않음fclose를 빼먹음fread반환값을 무시함while (!feof(fp))로 루프를 제어함- 바이너리 파일을 텍스트 모드로 엶
주의할 점
feof(fp)는 "이제 끝이다"가 아니라 "끝을 넘겨 읽으려 시도했다"는 신호입니다. 그래서 while (!feof(fp))로 루프를 돌리면 마지막 처리에서 한 번 더 엇나가기 쉽습니다. 읽기 함수의 반환값으로 루프를 제어하는 편이 맞습니다.
참고 링크
1 sources