응용프로그램이 시스템 호출로 운영체제에 파일을 요청 시 계속 검사를 해야하는 과정이 있기 때문에, 자주 하는건 시스템 성능을 저하시킴. 따라서 라이브러리를 만들고, 라이브러리의 함수를 호출하여 Library Buffer에서 데이터를 받아오는 것이 좋다.
따라서 C언어에서 Standard I/O Library를 정의하여 자체적으로 library buffering을 하여 System Call 횟수를 줄인다.
파일 입출력에서는 파일을 File Descriptor로 접근하였지만, 표준 입출력에서는 스트림 형태로 파일에 접근한다. 하나의 스트림을 다루기 위하여 FILE이라는 구조체가 정의되어 있는데, 스트림을 열면, 파일 구조체 포인터가 배정된다.
스트림 내부의 버퍼에서 Read하고 Write 시스템호출 동작을 큰 단위로 하기 때문에 시스템 호출 횟수(시스템 내부 접근 횟수)가 줄어든다.
커널에 의해 STDIN, STDOUT, STDERR 스트림은 프로세스가 자동으로 얻는다.
struct FILE {
char* _IO_read_ptr;
char* _IO_read_end;
char* _IO_read_base;
char* _IO_write_ptr;
char* _IO_write_end;
char* _IO_write_base;
int flags; // r/w 플래그나, 에러 정보
int _fileno; //스트림과 관련된 File Descriptor 번호
}
I/O 버퍼링 종류
line buffered : /n
에 의해 입출력이 발생
fully buffered : 버퍼가 가득 찬 경우에 입출력이 발생(stdin, stdout등)
unbuffered : 응용프로그램과 파일 사이에 버퍼를 사용하지 않음(stderr 등)
FILE *fopen(const char *pathname, const char *type)
FILE 포인터 반환
*type 종류
r, rb: O_RDONLY
w, wb: O_WRONLY | O_CREAT | O_TRUNC
a, ab: O_WRONLY | O_APPEND | O_CREAT => offset을 무시하고 맨 뒤에 추가
r+, r+b, rb+: O_RDWR
w+, w+b, wb+: O_RDWR | O_CREAT | O_TRUNC
a+, a+b, ab+: O_RDWR | O_APPEND | O_CREAT
FILE *freopen(const char *pathname, const char type, FILE fp)
fp를 pahtname 가리키도록 변경, open 후 dup2하는것과 동일한 동작
FILE *fdopen(int fd, const char *type)
이미 open된 fd를 스트림 형태로 다시 열어달라, 단 type은 open과 동일해야함, 운영체제에 open 시스템 호출을 하지는 않음
int fclose(FILE *fp)
0이면 정상종료, EOF면 에러
close시 내부 동작
출력 버퍼에 있는 자료는 저장, 입력 버퍼에 있는 자료는 버려짐
한 글자 받아오거나 에러시 EOF
매크로 형태로 구현한 fgetc, 속도는 빠르지만 함수를 인자로 줄 순 없다
stdin에서 한 글자 받아옴
c(EOF제외)를 다시 버퍼에 반납함(파일에 기록되는건 아님). \n같은 문자 읽었을 때 뒤로가기 위해 존재
fp에 c를 출력함, 에러시 EOF
fputc의 매크로 형태
stdout에 출력
최대 n개 문자를 fp에서 읽어 buf에 저장
\n이나 EOF만날 때 까지 or n개 문자 읽을 때 까지 읽고, 읽은 문자열의 마지막에 NULL을 채움
stdin에서 fgets, 하지만 크기 지정을 할 수 없어 버퍼 크기 넘기면 해킹가능
\n을 만날 때 까지 읽고, \n을 NULL로 대체하여 읽음
buf 출력, 실패나 에러는 NULL 출력
str을 fp에 write함, 양수면 성공, EOF 에러
stdout에 write함
끝이 str의 끝이 NULL이어야 한다.
fputs는 \n을 추가해주지 않고, puts는 쓸 때마다 \n을 추가해준다.
<Binary I/O 함수> : \n, NULL 등의 text는 중요하지 않고, R/W할 데이터의 size만 중요
==> 이진배열이나 구조체 입출력 가능
Read/Write한 nobj수 반환
size는 객체 1개 크기
nobj는 객체 수
<Offset 위치 관련> : 64bit 시스템에서 offset은 8byte이므로 long타입 offset가짐
현재의 offset 반환
whence 기준으로 offset만큼 이동, 0이면 성공, 나머지 에러
0으로 offset 되돌리기
32bit 컴퓨터 사용 시 offset을 long으로 표현할 수 없어, fpos_t라는 구조체를 통해 offset 표현
<에러 관련>
int ferror(FILE fp) 입출력 오류 발생 체크, _IOERR flag 저장
int feof(FILE fp) 파일의 끝(EOF) 도달 여부 체크, _IOEOF flag 저장
void clearerr(FILE *fp) _flags의 _IOERR, _IOEOF 삭제
0이 아니면 에러, 에러 정보는 FILE 구조체의 _flags에 저장
<버퍼 관련>
Buffering 되어있는 데이터를 운영체제에 시스템호출로 write 요청, 0이면 성공, EOF는 에러
0이면 성공, 나머진 실패, buf가 NULL이면 unbuffered, 기본은 fully buffered
setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ)와 같다. bufsiz는 기본 1byte
buf: 사용할 버퍼의 포인터
mode : Fully Buffered(_IOFBF), Line Buffered(_OILBF), Unbuffered(_IONBF)
size : 사용될 버퍼의 크기
<멀티쓰레드에서 파일 잠금>
이미 lock되어있는 stream에 대해서 풀릴때까지 계속대기
lock 획득 여부만 반환하고 기다리지는 않음
0이면 lock 성공, 0이 아니면 실패