[C++] 파일 입출력

junykim·2025년 1월 10일

파일 입출력 (File I/O)

파일 입출력은 C 언어 및 C++에서 제공하는 표준 라이브러리를 통해 쉽게 사용할 수 있습니다.
많이 사용되지는 않지만, 정확히 이해하고 필요한 상황에 적절히 사용할 줄 알아야 합니다.


1. 파일 입출력의 기본

  • C++의 fstream, C의 stdio.h 라이브러리를 사용.
  • 파일 입출력의 주요 포인트:
    1. 텍스트 모드이진 모드의 구분.
    2. 파일 포인터(File Pointer)의 이동 및 관리.
    3. 성능 향상을 위해 읽기/쓰기 호출(call) 횟수를 줄임.

2. 텍스트 모드 vs 이진 모드

텍스트 모드 (Text Mode)

  • 파일의 끝: 0x1A(EOF)로 처리.
  • 줄바꿈:
    • Windows: CR (0x0D) + LF (0x0A)
    • Linux: LF (0x0A)만 사용.
  • 서로 다른 OS에서 만든 텍스트 파일을 열면 줄바꿈 처리가 안 될 수 있음.

이진 모드 (Binary Mode)

  • 데이터 그대로 읽고 씀.
  • 텍스트와 달리 특별한 변환 없이 Raw Data 처리.

3. 파일 열기

  • fopen 모드:
    • "r": 읽기 전용.
    • "w": 쓰기 전용 (파일이 없으면 생성, 있으면 덮어씀).
    • "a": 추가 쓰기 모드 (파일 끝에 이어 씀).
    • "rb", "wb", "ab": 이진 모드.

4. 파일 크기 얻기 (C 스타일 예제)

  • 파일의 끝으로 이동 후 크기를 얻고, 다시 처음으로 이동하여 데이터 처리.
FILE *pFile = fopen("file.txt", "rb");
fseek(pFile, 0, SEEK_END);   // 파일 끝으로 이동
long size = ftell(pFile);    // 현재 위치(파일 크기) 반환
fseek(pFile, 0, SEEK_SET);   // 파일 처음으로 이동

char *buffer = malloc(size); // 파일 크기만큼 메모리 할당
fread(buffer, 1, size, pFile); // 파일 데이터 읽기
fclose(pFile);
free(buffer);                // 동적 메모리 해제

5. 파일 쓰기와 버퍼링

  • fwrite 함수:
    • 데이터를 버퍼에 먼저 씀.
    • 실제로 파일에 저장되는 시점은 버퍼가 가득 찼을 때.
  • 버퍼링 문제 해결:
    • fflush(FILE *stream): 버퍼 데이터를 강제로 밀어냄.
    • fclose(FILE *stream): 버퍼 비우기 및 파일 닫기.

예제: 데이터 저장

FILE *pFile = fopen("file.txt", "wb");
fwrite(data, sizeof(data), 1, pFile);
fflush(pFile); // 데이터를 강제로 저장
fclose(pFile); // 파일 닫기 (버퍼 비우기)

6. fread() 함수와 파일 읽기

  • fread 사용법:
size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
  • 반환값: 읽은 항목의 개수 (count).
  • 내부적으로 4KB 정도의 버퍼를 이용해 한 번에 데이터를 읽음.
  • 작은 단위(size = 1, count = 1)로 읽더라도, 실제로는 버퍼에서 데이터를 반환.
  • 성능을 위해 큰 덩어리로 데이터를 읽는 것이 유리.

예제: 파일 읽기

FILE *pFile = fopen("file.txt", "rb");
char buffer[1024];
size_t bytesRead = fread(buffer, 1, sizeof(buffer), pFile);
fclose(pFile);

7. 기타 유용한 함수

  • fseek(FILE *stream, long offset, int origin):
    • 파일 포인터 위치 이동.
    • origin:
      • SEEK_SET: 파일의 시작 위치.
      • SEEK_CUR: 현재 위치.
      • SEEK_END: 파일 끝.
  • ftell(FILE *stream):
    • 현재 파일 포인터 위치 반환.
  • rewind(FILE *stream):
    • 파일 포인터를 처음으로 이동시키며 상태 초기화.
  • fflush(FILE *stream):
    • 스트림 버퍼를 비우고 내용을 파일로 밀어냄.

8. 주의사항

  1. 로그 파일 작업:
    • 항상 append 모드(a)로 열어야 함.
    • 로그는 순차적으로 추가되기 때문에, 덮어쓰기가 발생하지 않도록 보장.
  2. 대용량 파일 처리:
    • 전체 파일을 메모리로 읽기 어려운 경우, 블록 단위로 작업.
  3. 운영체제의 버퍼링:
    • fflush()를 호출해도 OS의 캐시에 남아 있을 수 있음.
    • 파일을 안전하게 저장하려면 파일을 반드시 닫아야 함.

9. 파일 입출력 성능 최적화

  • 입출력 호출 횟수를 줄이는 것이 핵심.
  • 가능하면 파일 데이터를 한 번에 메모리로 읽은 후 작업.
  • 작은 크기의 데이터를 반복적으로 읽는 것은 비효율적.

0개의 댓글