8. 지정한 위치 읽고 쓰기 - pread(), pwrite()
System/System Programming

8. 지정한 위치 읽고 쓰기 - pread(), pwrite()


개요


  지난번 게시글에서는 lseek()를 통해 파일 오프셋을 원하는 곳으로 바꾸어서 파일 입출력을 하는 방법에 대해 다루어 보았다. 한편 리눅스에서는 lseek() 대신 읽고 쓸 파일 오프셋을 지정할 수 있는 read()와 write()와 비슷한 사촌격의 시스템 콜이 있다. 둘 모두 각각의 읽기, 쓰기 작업을 마친 후 파일 오프셋을 갱신하지 않는다.


pread()와 pwrite()


  pread() 시스템 콜을 사용하면 읽을 오프셋을 지정할 수 있다.


1
2
3
4
#include <unistd.h>
#define _XOPEN_SOURCE 500
 
ssize_t pread(int fd, void *buf, size_t count, off_t pos);
cs


  pread()를 사용하면 파일 디스크립터 fd에서 pos (지정된 오프셋) 에 있는 데이터를 buf에 count바이트만큼 읽는다.


  pwrite() 는 쓸 오프셋을 지정한다.


1
2
3
4
#include <unistd.h>
#define _XOPEN_SOURCE 500
 
ssize_t pwrite(int fd, const void *buf, size_t count, off_t pos);
cs


  pread()와 형태는 큰 차이가 없는 것 같다. buf에 담긴 데이터를 파일 디스크립터 fd의 pos 오프셋에 count 바이트만큼 쓴다.


  이 두 호출은 현재 파일의 오프셋을 무시하고 지정된 오프셋(pos)을 사용한다는 공통점이 있다. 나머지는 기존의 read(), write() 시스템 콜과 거의 유사하게 동작한다. 또한, 작업이 끝나도 파일 오프셋을 갱신하지 않는다는 특징을 가지고 있다. 하지만 read(), write(를 pread(), pwrite()와 혼용하게 되면 파일을 망가뜨릴 가능성이 있으니 조심하자.


  오프셋을 지정한 파일 읽기 / 쓰기는 lseek() 호출이 가능한 파일 디스크립터에서만 사용이 가능하다. 두 함수는 read(), write() 호출에 앞서 lseek()를 호출하는 방식과 유사하게 동작하지만, 몇 가지 차이점이 있다. 총 세 가지인데, 정리하면 다음과 같다.


① 작업 후 파일 오프셋을 원위치로 되돌리거나 임의의 오프셋에 접근해야 하는 경우에 쉽게 사용할 수 있다.


② 호출이 완료된 후 파일 포인터를 갱신하지 않는다.


lseek() 사용 시 발생할 수 있는 경쟁 상태를 피할 수 있다.


  스레드는 현재 파일 오프셋이 저장된 파일 테이블을 공유하기 때문에 어떤 스레드가 lseek()를 호출한 후, 읽기 / 쓰기 작업을 미처 수행하기도 전에 다른 스레드에서 파일 오프셋을 갱신하는 경우가 있다. 다시 말해, lseek()는 여러 스레드에서 같은 파일 디스크를 처리할 경우 안전하지 못하다는 것이다. 이런 경쟁 상태는 pread()와 pwrite()를 사용해서 회피할 수 있다.


'System > System Programming' 카테고리의 다른 글

7. 파일 탐색하기 - lseek()  (0) 2019.04.25
6. 파일 닫기 - close()  (0) 2019.04.24
5. 직접 입출력  (0) 2019.04.24
4. 동기식 입출력 - fsync(), fdatasync()  (2) 2019.04.22
3. 파일 쓰기 - write()  (0) 2019.04.16