프로그래밍/C, C++

C 언어 파일 입출력

argentdarae 2025. 4. 9. 23:36
반응형

C에서는 파일을 다루기 위해서는 운영체제가 제공하는 함수를 사용하거나 파일 스트림을 직접 읽고 쓰는 방식으로 구현해야 한다

 

파일 입출력 과정은 다음의 3단계로 이루어진다

  1. 파일을 연다 (파일 스트림 가져옴)
  2. 파일을 읽거나 사용한다 (파일 스트림 사용)
  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

fclose - cppreference.com

fgetc, getc - cppreference.com

fputc - cppreference.com

fputs - 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