2What — 파일 I/O란?
3- 프로그램이 실행 중 만든 데이터는 종료 시 사라짐 (RAM은 휘발성)
4- 파일 I/O: 디스크에 데이터를 읽고(Input) 쓰는(Output) 작업
5- C 표준 라이브러리는 $<stdio.h>$에 파일 \frac{I}{O} 함수를 제공
6- 핵심 추상화 두 가지: 스트림(stream)과 FILE 구조체
7Why — 왜 스트림이라는 추상화가 필요한가?
8- 디스크, 키보드, 네트워크 등 장치마다 읽기/쓰기 방식이 다름
9- 장치마다 별도 코드를 작성하면 프로그램이 하드웨어에 종속됨
10- 스트림은 "바이트가 흐르는 파이프"라는 단일 인터페이스를 제공 (Kernighan & Ritchie, 1988)
11- 수도꼭지 비유: 수원지가 댐이든 지하수든, 꼭지를 틀면 물이 나옴 → 프로그램은 데이터 출처를 몰라도 됨
12- 이 덕분에 fprintf() 하나로 화면 출력·파일 저장·로그 기록을 모두 처리 가능
13How — FILE 구조체와 스트림의 동작
14- FILE: 스트림의 상태를 저장하는 구조체 (버퍼 위치, 읽기/쓰기 모드, 에러 플래그 등)
15- 프로그래머가 직접 멤버에 접근하지 않음 → FILE * (포인터)로만 조작
16- 이는 불투명 포인터(opaque pointer) 패턴: 내부 구현을 숨기고 함수 인터페이스만 노출
173개의 기본 스트림 (프로그램 시작 시 자동 열림)
18- stdin: 표준 입력 (키보드) — scanf(), fgets()가 여기서 읽음
19- stdout: 표준 출력 (화면) — printf()가 여기에 씀
20- stderr: 표준 에러 (화면, 버퍼링 없음) — 에러 메시지 전용
21파일 열기/닫기 기본 흐름
22- 1단계: FILE\ *fp = fopen("data.txt",\ "r"); → 스트림 생성, FILE 구조체 할당
23- 2단계: fread(), fwrite(), fprintf() 등으로 읽기/쓰기
24- 3단계: fclose(fp); → 버퍼 플러시 + 자원 해제
25- fclose를 빠뜨리면 데이터 손실 발생 가능 (버퍼에 남은 데이터가 디스크에 안 씌어짐)
26- malloc/free와 동일한 패턴: 열었으면 반드시 닫는다
27텍스트 모드 vs 바이너리 모드
28- 텍스트 모드 ("r", "w"): OS가 개행 문자를 자동 변환 (Windows: \backslash r\backslash n ↔ \backslash n)
29- 바이너리 모드 ("rb", "wb"): 바이트를 있는 그대로 읽고 씀 — 이미지, 음성 파일 등에 필수
30- 잘못된 모드로 열면 데이터가 깨짐 → 모드 선택은 의도적이어야 함
31버퍼링 — 왜 즉시 쓰이지 않는가?
32- 디스크 접근은 RAM 대비 수만 배 느림 (Hennessy & Patterson, 2017)
33- C 라이브러리는 버퍼에 데이터를 모았다가 한꺼번에 디스크에 씀
34- 완전 버퍼링: 버퍼가 차면 플러시 (파일 기본값)
35- 줄 버퍼링: \backslash n을 만나면 플러시 (stdout 기본값)
36- 비버퍼링: 즉시 출력 (stderr 기본값)
37- fflush(fp)로 수동 플러시 가능
38에러 처리 — 방어적 코딩
39- fopen이 실패하면 NULL 반환 → 반드시 체크해야 함
40- 체크 없이 NULL 포인터를 fprintf에 넘기면 정의되지 않은 동작(UB)
41- 패턴: $if\ (fp == NULL)\ \{\ perror("fopen");\ return\ 1;\ \}$