read()로 읽기

가장 대표적인 읽기 메커니즘은 POSIX.1에 정의된 read() 시스템 콜을 사용하는 것입니다.

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t len);

read 시스템 콜을 호출할 때마다 fd가 참조하는 파일의 현재 파일 오프셋에서 len 바이트만큼 buf로 읽어 들입니다. 성공하면 buf에 쓴 바이트 만큼 숫자를 반환합니다. 실패하면 -1을 반환하며 errno를 설정합니다. 파일 오프셋은 fd에서 읽은 바이트 크기만큼 전진합니다.

unsigned long word;
ssize_t nr;

nr = read(fd, &word, (unsigned long));
if (nr == -1)
	// 에러

기본 사용법은 간단합니다. 위 예제는 파일 디스크립터로부터 읽어서 word에 저장합니다. 읽은 바이트 수는 unsigned long 타입 크기와 동일합니다. 반환값 nr은 읽은 바이트 숫자이며 오류가 발생했을 경우에는 -1을 반환합니다.

이런 단순한 구현 방법에는 두 가지 문제점이 있습니다. len 바이트만큼 모든 데이터를 읽지 못할 가능성과 점검 후 처리 과정이 빠져 있기 때문에 에러가 발생할 가능성이 있습니다.

반환값

read()가 len보다 작은 양수값을 반환하는 경우도 있습니다. 이런 현상에는 몇 가지 이유가 있는데, len 바이트보다 적은 바이트만 사용 가능하거나, 시그널이 시스템 콜을 중단시키거나, 파이프가 깨지는 등 이유는 다양합니다.

read()를 사용할 때 반환값이 0이 될 또 다른 가능성을 고려해야 합니다. read() 시스템 호출은 파일 끝을 알려주기 위해 0을 반환합니다. 이 경우 당연히 읽을 바이트가 남아 있지 않습니다. EOF는 에러로 취급되지 않으며 단순히 파일 오프셋이 파일에서 마지막으로 유효한 오프셋을 넘어갔기 때문에 더 이상 읽을 데이터가 없다는 사실을 알려줄 뿐입니다.

하지만 파일 끝에 도달한 경우와는 달리, len 바이트만큼 읽으라고 요청했지만 읽을 데이터가 없다면 read() 호출은 읽을 바이트가 생길 때까지 블록(잠자기)됩니다. 이는 EOF를 반환하는 앞선 동작 방식과 다릅니다. 다시 말해 '사용 가능한 데이터가 없음'과 '파일 끝' 사이에는 차이점이 존재합니다. EOF는 파일 끝에 도달했다는 의미가 있습니다.

어떤 에러는 복구가 가능합니다. 예를 들어 한 바이트도 읽기 전에 시그널이 read()를 중단시켰을 경우, read()는 -1을 반환하며 errno를 EINTR로 설정합니다. 이 경우 다시 한 번 읽기 요청이 가능합니다.

사실상 read() 호출은 다음과 같은 다양한 가능성을 가지고 있습니다.