3장에서는 표준 c 라이브러리를 통해 파일을 작업하는 것을 설명한다.
❗️하지만 보통 사용자 application에서는 필드나 문자열 등의 입출력 연산이 필요한 경우가 대부분임.
❗️시스템 콜을 이용하여 파일 입출력 작업을 하면 호출할 때마다 커널을 통해 입출력을 수행하여 시스템 효율이 떨어질 수 있음.
❗️따라서, 사용자 application code 레벨에서 인위적으로 버퍼링을 구현하는데, 이미 있는 사용자 버퍼링 구현체를 가져다 씀 (표준 입출력 라이브러리나 표준 c++ iostream).
표준 입출력에서는 파일 디스크립터 대신 파일 포인터
를 사용. 파일 포인터는 c 라이브러리 내부에서 파일 디스크립터로 맵핑됨.
읽거나 쓰기 위해 fopen()을 사용해서 파일을 엶.
#include <stdio.h>
FILE * fopen (const char *path, const char *mode);
path
를 mode
에 따라 원하는 용도로 새로운 스트림을 만듦.mode
이미 열린 파일 디스크립터(fd)를 통해 스트림을 만듦.
#include <stdio.h>
FILE * fdopen (int fd, const char *mode);
#include <stdio.h>
int fclose (FILE *stream);
#define _GNU_SOURCE
#include <stdio.h>
int fcloseall (void);
#include <stdio.h>
int fgetc (FILE *stream);
stream
에서 다음 문자를 읽고 unsigned char 타입을 int 타입으로 변환해서(EOF나 에러를 알려주기 위해) 반환.#include <stdio.h>
char * fgets (char *str, int size, FILE *stream);
stream
에서 size
보다 하나 적은 내용을 읽어서 결과를 str
에 저장.c 구조체 같은 복잡한 바이너리 데이터를 읽을 때 사용.
#include <stdio.h>
size_t fread (void *buf, size_t size, size_t nr, FILE *stream);
stream
에서 각각 크기가 size
바이트인 element를 nr
개를 읽어서 buf
가 가리키는 버퍼에 저장.#include <stdio.h>
int fputc (int c, FILE *stream);
c
로 지정한 바이트를 (unsigned char로 변환한 후에) stream
이 가리키는 스트림에 씀.#include <stdio.h>
int fputs (const char *str, FILE *stream);
str
이 가리키는 NULL로 끝나는 문자열 전부를 stream
이 가리키는 스트림에 기록.#include <stdio.h>
size_t fwrite (void *buf, size_t size, size_t nr, FILE *stream);
buf
가 가리키는 데이터에서 size
크기의 element nr
개를 stream
에 씀.#include <stdio.h>
int fseek (FILE *stream, long offset, int whence);
offset
과 whence
에 따라 stream
에서 파일 위치를 조작.여기 3장에서 설명하는 함수들은 모두 c라이브러리가 관리하는 버퍼를 사용하는데 이 버퍼는 사용자 영역에 위치함. 커널이 유지하는 버퍼는 커널영역에 위치함.
fflush()는 사용자 버퍼를 커널로 비워서 스트림에 쓴 모든 데이터가 write()를 통해 실제로 디스크에 기록되도록 만드는 인터페이스.
#include <stdio.h>
int fflush (FILE *stream);
stream
에 있는 쓰지 않은 데이터를 커널로 비움.스레드 세이프(Thread-safe) 는 멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없음을 뜻한다. _위키피디아
❗️멀티스레드 환경에서 동작해도 원래 의도한 대로 동작하는 것을 스레드세이프 하다고 할 수 있음.
❗️스레드를 지원하는 운영체제는 락 메커니즘을 지원하는데, 표준 입출력은 이를 활용해 단일 프로세스 내의 여러 스레드가 동시에, 심지어는 같은 스트림에 대해서 표준 입출력을 호출할 수 있도록 함.
❗️락을 걸면 critical section(다른 스레드의 간섭 없이 실행할 수 있는 코드)을 설정할 수 있음.
락을 거는 함수
#include <stdio.h>
void flockfile (FILE *stream);
stream
의 락이 해제될 때까지 기다린 후에 락 counter를 올리고 락을 얻은 다음, 스레드가 stream
을 소유하도록 만듦.락을 해제하는 함수
#include <stdio.h>
void funlockfile (FILE *stream);
stream
과 연관된 락 counter를 하나 줄임.stream
의 소유권을 포기해서 다른 스레드가 락을 얻을 수 있도록 함.