NAME

read - 파일 디스크립터에서 읽기

SYNOPSIS

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

DESCRIPTION

read()는 파일 디스크립터 fd에서 buf가 가리키는 버퍼로 최대 count 바이트를 읽어 들이려고 시도한다.

위치 탐색을 지원하는 파일에선 파일 오프셋에서 읽기 동작이 시작하며 읽은 바이트 수만큼 파일 오프셋이 증가한다. 파일 오프셋이 파일 끝이나 그 너머에 있으면 아무것도 읽지 않으며 read()가 0을 반환한다.

count가 0인 경우에 read()가 아래에서 설명하는 오류들을 탐지할 수도 있다. 아무 오류도 없으면, 또는 read()에서 오류 검사를 하지 않는 경우면 count가 0인 read()가 0을 반환하며 달리 아무 영향도 없다.

POSIX.1에 따르면 countSSIZE_MAX보다 큰 경우의 결과는 구현에서 규정한다. 리눅스에서의 상한에 대해선 NOTES 참고.

RETURN VALUE

성공 시 읽은 바이트 수를 반환하며 (0은 파일 끝을 나타냄) 파일 위치가 그만큼 진행한다. 그 수가 요청했던 바이트 수보다 적더라도 오류가 아니다. 예를 들어 (파일 끝 가까이에 있었거나, 파이프나 터미널에서 읽고 있거나 해서) 실제 가용 바이트가 적어서일 수도 있고, 인터럽트에 의해 read()가 중단돼서 일 수도 있다. NOTES도 참고.

오류 시 -1을 반환하며 오류를 나타내도록 errno를 설정한다. 이 경우에 파일 위치가 (있는 경우에) 바뀌는지는 명세돼 있지 않다.

ERRORS

EAGAIN
파일 디스크립터 fd가 소켓 아닌 파일을 가리키고 있고 논블로킹 표시(O_NONBLOCK)가 되어 있는데 읽기가 블록하려 했다. O_NONBLOCK 플래그에 대한 자세한 내용은 open(2) 참고.
EAGAIN 또는 EWOULDBLOCK
파일 디스크립터 fd가 소켓을 가리키고 있고 논블로킹 표시(O_NONBLOCK)가 되어 있는데 읽기가 블록하려 했다. POSIX.1-2001에서는 이 경우 어느 쪽이 반환되는 것도 허용하며 두 상수가 같은 값이어야 한다고 요구하지 않는다. 따라서 이식 가능한 응용에서는 두 가능성을 모두 확인하는 게 좋다.
EBADF
fd가 유효한 파일 디스크립터가 아니거나 읽기용으로 열려 있지 않다.
EFAULT
buf가 접근 가능한 주소 공간 밖에 있다.
EINTR
데이터를 읽기 전에 시그널에 의해 호출이 중단되었다. signal(7) 참고.
EINVAL
fd가 읽기에 적합하지 않은 객체에 연결돼 있다. 또는 O_DIRECT 플래그를 써서 파일을 열었는데 buf에 지정한 주소나 count에 지정한 값, 또는 파일 오프셋이 올바로 정렬돼 있지 않다.
EINVAL
timerfd_create(2) 호출을 통해 fd가 생성되었는데 잘못된 크기의 버퍼를 제공했다. 자세한 내용은 timerfd_create(2) 참고.
EIO
I/O 오류. 예를 들어 프로세스가 백그라운드 프로세스 그룹에 있으면서 제어 터미널에서 읽기를 시도하는데, SIGTTIN을 무시 내지 차단하고 있거나 프로세스 그룹이 고아인 경우에 발생하게 된다. 디스크나 테이프에서 읽는 도중에 저수준 I/O 오류가 생긴 경우에도 발생할 수 있다. 추가로 네트워크 파일 시스템에서 EIO가 발생할 수 있는 또 다른 경우는 파일 디스크립터에서 권고형 락을 가져갔는데 그 락이 사라졌을 때다. 자세한 내용은 fcntl(2)락 상실 절 참고.
EISDIR
fd가 디렉터리를 가리키고 있다.

fd에 연결된 객체에 따라서 다른 오류가 발생할 수도 있다.

CONFORMING TO

SVr4, 4.3BSD, POSIX.1-2001.

NOTES

size_tssize_t 타입은 각각 부호가 없거나 있는 정수 데이터 타입이며 POSIX.1에 명세돼 있다.

리눅스에서 read()는 (그리고 유사한 시스템 호출들은) 최대 0x7ffff000 (2,147,479,552) 바이트까지 이동시키며 실제 이동된 바이트 수를 반환한다. (32비트 시스템과 64비트 시스템 모두에서 그렇다.)

NFS 파일 시스템에서 데이터를 작게 읽으면 처음에만 타임스탬프가 갱신되고 이어지는 호출에서는 갱신되지 않을 수 있다. 이는 클라이언트 측 속성 캐싱 때문인데, 대부분의 NFS 클라이언트에선 st_atime(최근 파일 접근 시간) 갱신을 서버에게 맡기므로 클라이언트 캐시만으로 읽기에 성공하면 서버 측 읽기 동작이 없어서 서버에서 st_atime 갱신이 이뤄지지 않기 때문이다. 클라이언트 측 속성 캐싱을 끄면 유닉스의 동작 방식을 얻을 수 있기는 한데, 대부분의 경우 이는 서버 부하를 상당히 증가시켜서 성능을 떨어뜨리게 된다.

BUGS

POSIX.1-2008/SUSv4의 XSI 2.9.7절("Thread Interactions with Regular File Operations")에 따르면:

다음 함수들 모두는 정규 파일이나 심볼릭 링크에 동작할 때 POSIX.1-2008에 명세된 효력들에 있어서 서로에게 원자적이다.

이어서 나오는 API들 중에는 read()readv(2)가 있다. 그리고 스레드 (및 프로세스) 간에 원자적이어야 하는 효력들 중에는 파일 오프셋 갱신이 있다. 하지만 리눅스 버전 3.14 전에선 그렇지 않았다. 열린 파일 기술 항목(open(2) 참고)을 공유하는 두 프로세스가 동시에 read()를 (또는 readv(2)를) 수행하면 그 I/O 동작들이 파일 오프셋 갱신 측면에서 원자적이지 않아서 두 프로세스가 읽어서 얻은 데이터 블록들이 겹칠 수도 있었다. 리눅스 3.14에서 이 문제가 고쳐졌다.

SEE ALSO

close(2), fcntl(2), ioctl(2), lseek(2), open(2), pread(2), readdir(2), readlink(2), readv(2), select(2), write(2), fread(3)


2021-03-22