C, C++ & Linux

[C & Linux] 파일 디스크립터(file Descriptor) & 파일 입출력 관련 시스템콜 함수

서노리 2022. 4. 7. 03:00
반응형

파일 디스크립터(File Descriptor)

Linux/Unix에서 파일은 데이터를 읽을 수 있거나 데이터를 쓸 수 있는 모든 객체를 말한다. 일반적인 정규 파일부터 디렉토리, 소켓, 파이프, 터미널 등등 모든 디바이스도 파일로 취급한다. Linux/Unix에서 프로세스가 이 파일들을 바이트 단위의 입출력으로 다룰 수 있게 하고, 커널 내부의 자료 구조들과의 연결 통로 역할을 하게 하는 것이 파일 디스크립터이다.

 

프로세스가 실행 중에 파일을 open하면 커널은 해당 프로세스의 파일 디스크립터 숫자 중 사용하지 않는 가장 작은 값을 할당해준다. 그다음 프로세스가 열려있는 파일에 시스템 콜을 이용해서 접근할 때, 파일 디스크립터 값을 이용해서 파일을 지칭할 수 있는 것이다.

기본적으로 할당되는 파일디스크립터는 0(표준 입력), 1(표준 출력), 2(표준 에러)가 있다. 즉, 사용자가 open 한 파일에 대한 파일 디스크립터는 3부터 할당된다.


파일 입출력 관련 기본적인 시스템 콜 함수

Open(2)

파일을 오픈하거나 생성할 때 사용하는 시스템 콜 함수
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int oflag);
int open(const char *pathname, int oflag, mode_t mode);

// 리턴 값: 성공 시 파일 디스크립터, 에러시 -1

const char *pathname열고자 하는 파일의 경로(상대 경로 / 절대 경로 모두 가능)

 

int oflag : 파일이 어떤 용도로 사용될 것인지를 결정하는 옵션

 

- 반드시 사용해야 하는 플래그(셋 중 하나)

  • O_RDONLY - 파일을 읽기 전용으로만 오픈
  • O_WRONLY - 파일을 쓰기 전용으로만 오픈
  • O_RDWR - 파일을 읽기와 쓰기가 모두 가능하도록 오픈

 

- 선택적으로 사용할 수 있는 플래그

  • O_APPEND - 파일의 원래 데이터를 유지하면서 새로운 데이터를 그 파일의 끝에 추가하고자 할 때 사용
  • O_CREAT - 파일이 존재하지 않을 경우 같은 이름의 파일을 생성. 3번째 인자인 파일의 mode와 함께 지정해야 한다.
  • O_EXCL - O_CREAT과 함께 쓰이며 만약 파일이 이미 존재한다면 open()이 실패하고 에러를 리턴
  • O_TRUNC - O_RDWR 또는 O_WRONLY 모드인 경우에 해당 파일이 이미 존재할 경우 그 파일은 길이가 0이 되면서 이전 데이터를 모두 잃게 된다.

 

mode_t mode : O_CREAT 옵션을 쓸 때 필수적으로 사용해야하는 옵션으로, 8진수 형태로 나타내며 파일을 읽기, 쓰기, 실행할 사용자의 권한을 지정한다.

 

S_IRWXU        파일 소유주에게 읽기, 쓰기, 실행 권한을 설정.
S_IRUSR        파일 소유주에게 읽기 권한을 설정.
S_IWUSR        파일 소유주에게 쓰기 권한을 설정.
S_IXUSR        파일 소유주에게 실행 권을을 설정.
S_IRWXG        파일 그룹에게 읽기, 쓰기, 실행 권한을 설정.
S_IRGRP        파일 그룹에게 읽기 권한을 설정.
S_IWGRP        파일 그룹에게 쓰기 권한을 설정.
S_IXGRP        파일 그룹에게 실행 권한을 설정.
S_IRWXO        다른 사용자에게 읽기, 쓰기, 실행 권한을 설정.
S_ROTH        다른 사용자에게 읽기 권한을 설정.
S_WOTH        다른 사용자에게 쓰기 권한을 설정.
S_XOTH        다른 사용자에게 실행 권한을 설정.

 

또는 세자리 수 8진수 형태의 권한 고유값을 넣어줄 수 있다.  예를 들어 0751은 111 101 001 이므로 파일 주인은 모든 권한을 가지고, 파일 주인이 속한 그룹은 읽기, 실행 권한을 가지고, 그 외 유저는 실행 권한만 가지는 것을 의미한다.

 

※ 리눅스 파일 권한에 대한 포스팅 : 리눅스의 파일 권한 (Permission)

 

 

Close(2)

오픈한 파일을 닫을 때 사용하는 시스템 콜 함수
#include <unistd.h>
int close(int fd);

// 리턴 값: 성공 시 0, 에러 시 -1

int fd : 닫을 파일의 파일 디스크립터

 

 

Creat(2)

파일을 생성할 때 사용하는 시스템 콜 함수
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

int creat(const char *pathname, mode_t mode);

// 리턴 값: 성공 시 쓰기전용으로 열린 파일 디스크립터, 에러시 -1

const char *pathname : 생성할 파일의 경로

mode_t mode : 8진수 형태로 나타내며 파일을 읽기, 쓰기, 실행할 사용자의 권한을 지정한다.

 

open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); 와 동일한 역할을 한다. 즉, creat()으로 생성한 파일은 접근 모드가 쓰기 전용으로 생성되어 그 파일을 다시 읽기 위해서는 일단 파일을 close() 한 후 읽기쓰기 혼용 권한으로 다시 오픈해야 한다.

 

 

lseek(2)

오픈된 파일의 오프셋 위치를 명시적으로 변경해주는 시스템 콜 함수
#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

// 리턴 값: 성공 시 새 파일 오프셋, 에러 시 -1

 

int fd : 조정할 파일의 파일 디스크립터

off_t offset : 기준점으로부터 이동할 바이트 수

int whence : 기준점

  • SEEK_SET(0) - 파일의 맨 처음
  • SEEK_CUR(1) - 파일의 현재 오프셋 위치
  • SEEK_END(2) - 파일의 맨 마지막

 

※ lseek(fd, 0, SEEK_END); 를 이용하여 파일의 크기를 알 수 있다.

 

 

read(2)

오픈된 파일에서 데이터를 읽을 때 사용하는 시스템 콜 함수
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);

// 리턴 값: 성공시 읽은 바이트 수, 에러 시 -1

int fd : 읽을 파일의 파일 디스크립터

void *buf : 읽어 들일 데이터를 저장할 배열

size_t nbytes : 읽어들일 데이터의 최대 길이(buf의 길이보다 커서는 안됨)

 

read() 호출이 완료되면 파일의 현재 오프셋 위치는 이전 오프셋 위치에서 실제 읽은 바이트 수만큼 이 더해진 값으로 갱신된다. 이때 리턴 값은 실제로 읽은 바이트 수이며 읽기를 요청한 바이트 수보다 적을 수 있다. (읽는 도중에 파일의 끝을 만난 경우)파일의 끝을 만난 이후에도 read()를 호출한다면 0을 리턴한다.

 

 

write(2)

오픈된 파일에 데이터를 쓸 때 사용하는 시스템 콜 함수
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);

// 리턴 값: 성공시 기록된 바이트 수, 에러 시 -1

int fd : 데이터를 쓸 파일의 파일 디스크립터

const void *buf : 쓰고자 하는 데이터가 담긴 버퍼

size_t nbytes : 쓰고자 하는 데이터의 길이(buf의 길이보다 커서는 안됨)

 

write() 호출이 완료되면 파일의 현재 오프셋 위치는 이전 오프셋 위치에서 실제 쓴 바이트 수만큼 이 더해진 값으로 갱신된다. 그리고 리턴 값도 실제로 쓴 바이트 수가 된다. 그러나 read()와 달리 쓰기를 요청한 바이트보다 실제로 쓴 데이터의 바이트가 더 적은 값이 될 수 없다. 두 값이 다르다면 어디선가 에러가 발생한 것이다.

 


 

반응형

'C, C++ & Linux' 카테고리의 다른 글

[Linux] 리눅스의 파일 권한 (Permission)  (0) 2022.04.07
[Linux] 리눅스 기본 명령어  (0) 2022.03.08