`fopen`, `fopen_s` 함수

fopen, fopen_s 함수 (fopen, fopen_s)

C에서 파일을 다루려면 먼저 그 파일을 열어야 해요. fopen은 파일 이름과 접근 모드를 주면 그 파일과 연결된 FILE* 스트림을 돌려주는, 파일 입출력의 가장 첫 관문이에요. 읽을지 쓸지, 덮어쓸지 이어 쓸지 같은 건 모두 mode 문자열로 정해요.

출처: cppreference

본문

함수 원형

<stdio.h>에 정의돼 있어요.

FILE* fopen( const char* filename, const char* mode );                   // (1) (until C99)
FILE* fopen( const char* restrict filename, const char* restrict mode ); // (1) (since C99)
errno_t fopen_s( FILE* restrict* restrict streamptr,
                 const char* restrict filename,
                 const char* restrict mode );                            // (2) (since C11)

설명 (Explanation)

  1. filename이 가리키는 파일을 열고, 그 파일과 연결된 파일 스트림의 포인터를 돌려줘요. mode가 파일 접근 모드를 결정해요.
  2. (1)과 같지만, 파일 스트림 포인터를 streamptr에 써 주고, 다음 오류들을 런타임에 감지해 현재 설치된 제약 처리 함수(constraint handler)를 호출해요.
  • streamptr이 널 포인터
  • filename이 널 포인터
  • mode가 널 포인터

다른 모든 경계 검사(bounds-checked) 함수와 마찬가지로, fopen_s는 구현이 __STDC_LIB_EXT1__을 정의하고, 사용자가 <stdio.h>를 포함하기 전에 __STDC_WANT_LIB_EXT1__을 정수 상수 1로 정의했을 때만 쓰는 게 보장돼요.

매개변수 (Parameters)

  • filename — 파일 스트림과 연결할 파일 이름
  • mode — 파일 접근 모드를 결정하는 널 종료 문자열
  • streamptr — 함수가 결과를 저장할 포인터를 가리키는 포인터(출력 매개변수)

파일 접근 플래그 (File access flags)

파일 접근 mode 문자열 의미 설명 파일이 이미 있으면 파일이 없으면
read "r" 읽기 읽기용으로 파일 열기 처음부터 읽기 열기 실패
write "w" 쓰기 쓰기용으로 파일 만들기 내용 파괴 새로 만들기
append "a" 이어 쓰기 파일에 이어 쓰기 끝에 쓰기 새로 만들기
read extended "r+" 읽기/쓰기 읽기/쓰기용으로 파일 열기 처음부터 읽기 오류
write extended "w+" 쓰기/읽기 읽기/쓰기용으로 파일 만들기 내용 파괴 새로 만들기
append extended "a+" 이어 쓰기/읽기 읽기/쓰기용으로 파일 열기 끝에 쓰기 새로 만들기

몇 가지 플래그를 더 짚어 볼게요.

  • "b" 플래그는 선택적으로 붙여 바이너리 모드로 열 수 있어요. POSIX에서는 아무 효과가 없지만, Windows에서는 '\n''\x1A'의 특별 처리를 꺼 줘요.
  • append 접근 모드에서는 파일 위치 표시자가 어디 있든 데이터는 항상 파일 끝에 쓰여요.
  • mode가 위에 나열된 문자열 중 하나가 아니면 동작이 정의되지 않아요. 일부 구현은 추가 모드(예: Windows)를 지원하기도 해요.
  • 갱신(update) 모드('+')에서는 입력과 출력을 모두 할 수 있는데, 출력 뒤에 입력을 하려면 그 사이에 fflush, fseek, fsetpos 또는 rewind를 호출해야 해요. 반대로 입력 뒤에 출력을 하려면 fseek, fsetpos, rewind가 필요해요(입력 연산이 파일 끝을 만난 경우는 예외).
  • "x" 플래그는 "w""w+"에 붙여서, 파일이 이미 존재하면 덮어쓰지 않고 실패하도록 만드는 기능이에요. (C11부터)
  • fopen_s/freopen_s에서 "w""a"로 만든 파일은 다른 사용자가 접근하지 못하게 권한이 설정돼요. 기본 fopen 권한을 쓰려면 "w""a"로 시작하는 지정자 앞에 "u" 플래그를 붙여요. (C11부터)

반환값 (Return value)

  1. 성공하면 새 파일 스트림의 포인터를 돌려줘요. filename이 대화형 장치가 아니라면 스트림은 완전 버퍼링(full buffering)돼요. 오류가 나면 널 포인터를 돌려주는데, POSIX는 이 경우 errno를 설정하도록 요구해요(원문에 'POSIX requires'가 중복 표기되어 있어요).
  2. 성공하면 0을 돌려주고 *streamptr에 새 파일 스트림 포인터를 써 줘요. 오류가 나면 0이 아닌 오류 코드를 돌려주고(단 streamptr 자체가 널이 아니라면) *streamptr에 널 포인터를 써 줘요.

주의할 점 (Notes)

filename의 형식은 구현이 정의하는데, 반드시 파일을 가리킬 필요는 없어요(예: 콘솔이나 파일시스템 API로 접근 가능한 다른 장치일 수도 있어요). 지원하는 플랫폼에서는 절대 경로나 상대 경로를 포함할 수 있어요.

예제 (Example)

"w+" 모드로 파일을 열어 문자열을 쓰고, 처음으로 되돌아간 뒤 한 글자씩 읽어 검증하는 예시예요.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    const char* fname = "/tmp/unique_name.txt"; // or tmpnam(NULL);
    int is_ok = EXIT_FAILURE;

    FILE* fp = fopen(fname, "w+");
    if (!fp)
    {
        perror("File opening failed");
        return is_ok;
    }

    fputs("Hello, world!\n", fp);
    rewind(fp);

    int c; // note: int, not char, required to handle EOF
    while ((c = fgetc(fp)) != EOF) // standard C I/O file reading loop
        putchar(c);

    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
    {
        puts("End of file is reached successfully");
        is_ok = EXIT_SUCCESS;
    }

    fclose(fp);
    remove(fname);
    return is_ok;
}

가능한 출력:

Hello, world!
End of file is reached successfully

같이 보기 (See also)

  • fclose — 파일 닫기
  • fflush — 출력 스트림을 실제 파일과 동기화
  • freopen/freopen_s — 기존 스트림을 다른 이름으로 다시 열기