C++/linux

(1) errno와 파일 입출력

로파이 2022. 5. 10. 14:24

리눅스 운영체제에서 사용되는 시스템 함수는 에러가 발생했을 시 <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