리눅스 운영체제에서 사용되는 시스템 함수는 에러가 발생했을 시 <error.h> 헤더에 정의된 전역 변수에 에러코드가 저장된다.
extern int errno;
에러 코드에 대한 에러 메시지를 편하게 출력하기 위한 방법은 다음과 같다.
#include <stdio.h>
void perror (const char* str);
// ex
if (open("file.txt", O_RDONLY) == -1)
{
perror("open failed.");
}
파일 열기 open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open (const char* name, int flags);
int open (const char* name, int flags, mode_t mode);
- flags 인자 : O_RDONLY, O_WRONLY, O_RDWR (읽기 전용/ 쓰기 전용/ 읽기 쓰기 전용)
- mode 인자 : 파일을 새로 생성할 경우 부여할 권한 비트 ex) 0777 (모든 읽기/쓰기/실행 권한) / 0644 소유자 읽기/쓰기 나머지 읽기 모드
성공하면 맵핑된 파일 디스크립터가 반환된다. 실패시 -1이 반환.
파일 생성 creat()
int creat (const char* name, mode_t mode);
open (name, O_WRONLY | O_CREAT| O_TRUNC, mode); 를 실행한 것과 같다.
파일 디스크립터를 통해 읽기 read()
#include <unistd.h>
ssize_t read (int fd, void* buf, size_t len);
fd가 참조하는 파일 오프셋에서 len만큼 읽어드려 buf에 복사한다.
성공시 읽어들인 바이트 수가 반환되며 그 수 만큼 파일 오프셋이 갱신된다.
실패시 -1을 반환.
ssize_t는 32bit에서 4바이트 64bit에서 8바이트 부호있는 정수를 의미.
반환값 상황
- len 만큼 반환 : 정상적으로 읽음.
- len 보다 작은 값 : 실제 데이터가 len보다 작은 경우 (EOF를 만나 일찍 반환). 혹은 시그널에 의해 읽기 도중 중단되었음.
- 0을 반환 : EOF, 더 이상 읽을 데이터가 없음.
- -1을 반환 : EINTR (바이트를 읽기 전 시그널이 도착, 다시 함수를 호출하면 된다.), EAGAIN(open에 flags 인자로 O_NONBLOCK을 넘겨 논블록 호출에서 읽을 데이터가 없음), 나머지 (심각한 에러)
파일 디스크립터를 통해 쓰기 write()
#include <unistd.h>
ssize_t write (int fd, const void * buf, size_t count);
파일 디스크립터에 맵핑된 파일에 buf 데이터를 count 만큼 쓴다.
실제 쓰여진 바이트 수가 반환 되며 실패시 -1을 반환
write() 동작 방식
사용자 영역 buf에서 커널 버퍼로 데이터가 쓰는 시스템 함수를 호출한다. 이 때, 리눅스 커널은 쓰여진 데이터를 바로 디스크로 동기화 시키지 않고 나중에 적절한 시점에서 커널 버퍼를 한꺼번에 동기화 시킨다. (지연 쓰기)
디스크로 데이터 동기화 fsync()와 fdatasync()
데이터가 디스크로 동기화되도록 유도하는 함수
#include <unistd.h>
int fsync (int fd);
int fdatasync (int fd);
fsync() : 파일 디스크립터에 해당하는 모든 변경점을 디스크에 기록한다.
fdatasync() : 파일 디스크립터에 해당하는 모든 데이터 변경점만 디스크에 기록한다.
if (fsync(fd) == -1)
{
perror("fsync failed.");
}
sync()
최적화가 조금 부족하지만 해당 시스템 호출은 모든 버퍼 내용을 디스크에 동기화한다.
void sync(void);
파일 닫기 close
#include <unistd.h>
int close (int fd);
닫기에 성공하면 0을 반환하고 실패하면 -1을 반환하며 errno가 설정된다.
if (close(fd) == -1)
{
perror("close failed");
}
파일 오프셋 조정하기 lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek (int fd, off_t pos, int origin);
origin 인자에 따라 오프셋 위치 조정이 다르게 일어난다.
- SEEK_CUR : 현재 파일 오프셋에서 pos만큼 움직인다. pos는 양/음의 정수 모두 가능하다.
- SEEK_END : 파일 크기만큼에서 pos만큼 오프셋을 움직인다.
- SEEK_SET : 현재 파일 오프셋을 pos로 설정한다.
성공 시 조정된 오프셋이 반환되고 실패 시 -1을 반환한다.
지정한 위치 읽고 쓰기
다음 함수는 읽고 쓰는 동작은 동일하지만 파일 오프셋을 갱신하지 않는다.
#include <unistd.h>
ssize_t pread (int fd, void* buf, size_t count, off_t pos);
ssize_t pwrite(int fd, void* buf, size_t count, off_t pos);
파일 디스크립터 fd에 대해 pos 오프셋 기준 count 만큼 buf 데이터로 읽거나 쓰는 작업을 수행한다.
'C++ > linux' 카테고리의 다른 글
(6) Pthread 쓰레드 / PMutex 뮤텍스 (0) | 2022.05.12 |
---|---|
(5) 프로세스 관리 (0) | 2022.05.11 |
(4) 고급 입출력 readv/writev/epoll/mmap (0) | 2022.05.10 |
(3) 버퍼 입출력 (0) | 2022.05.10 |
(2) 다중 입출력 select와 poll (0) | 2022.05.10 |