[systemprogramming/systemcall] systemcall-function 2

kim_sang_ june·2023년 4월 16일
0

강의 필기

목록 보기
3/3

file IO

UNIX 시스템에서는 수많은 종류의 IO(input/output)을 다루기 위해 file을 다루는 것으로 통일하여 설계되었다.

UNIX에서 모든 IO는 device에 상관없이 file을 open/close/read/write 하는 것으로 제어 할 수 있다.
이는 /dev에 속한 special file로 구현된다.

UNIX file은 byte의 나열이다.(sequence of byte, stream of byte)

기본구조

open / close / read / write 를 사용해 모든 file을 다룰 수 있으며 이는 모든 입출력 device 또한 다룰 수 있음을 의미한다.

우선 open을 이용해 file을 열어야한다.
이때 file descriptor이 반환되어 파일이 열려있는 동안은 이 file descriptor을 사용해 파일을 가리킨다.

read 함수를 이용해 file에 적힌 데이터를 읽어 들일 수 있다.(input)

write 함수를 이용해 file에 데이터를 수정, 추가 할 수 있다.(output)

close함수로 열린 file을 닫는다.

open( )

파일을 여는 함수

int open(const char \*path, int flag)
: 기존 파일을 여는 함수
int open(const char \*path, int flag, mode_t mode)
: 새로운 파일을 생성하는 함수
path로 파일 경로를 넘겨주게 되면 해당 파일을 열어 file-descriptor를 반환하는 함수 이다.
flag parameter을 통해 여러 옵션을 부여할 수 있다
mode를 이용해 권한 정보를 부여 할 수 있다.

  • 자주 사용하는 옵션
    O_RDWR : read and write
    O_CREAT : 이미 존재하는 파일이면 덮어쓰지 않고 함수를 실행하지 않음. 새로운 파일을 만들때만 작동
    O_EXCL : O_CREAT 와 같이 쓰며 파일이 이미 존재한다면 error 반환
    +옵션은 OR(||)연산자를 이용해 여러개를 동시에 적용할 수 있다.
여러 다른 옵션들

O_RDONLY : 읽기 전용
O_WRONLY : 쓰기 전용

O_APPEND : file offset을 file 끝으로 이동 O_TRUNC : 파일 내용을 싹 지우고 열기 O_NOCTTY: prevents an opened device from becoming a controlling terminal

### 자동으로 열려있는 함수 표준 입출력 장치라고 불리는 장치들은 우리가 굳이 open() 하지 않아도 사용할 수 있다.
  • standard input - keyboard
    표준입력 장치인 키보드는 이미 열려있다.
    file descriptor은 STDIN_FILENO으로 접근 가능하다.(실제 값 0)
  • standard output - screen
    표준 출력 장치인 화면은 이미 열려있다.
    file descriotor은 STDOUT_FILENO로 접근 가능하다(실제 값 1)
  • srandard error device - screen
    표준 에러 출력 장치는 화면이다. 이때 error의 출력은 standard output보다 우선순위를 갖는다고 보면 된다.(실제 값 2)
    STDERR_FILENO로 접근 가능하다.

#include <fcntl.h>
#include <sys/stat.h>

read( )

file의 byte들을 읽어오는 함수이다.

ssize_t read(int files, void \* buf, size_t nbyte)
ssize_t : int 값으로 읽어들인 문자의 개수를 반환한다.
files : 대상 파일의 file descriptor값(open()의 return값)을 넣어주면 된다.
buf : 읽어들인 글자들을 저장할 buffer이다. 배열의 형태로 전달한다.
nbyte : 읽어들일 문자의 개수이다. 보통의 경우 buf 크기와 같다.

read 함수가 요청한 것보다 적은 수의 byte를 읽을 수도 있다.

보통은 buffer의 개수만큼 nbyte를 설정해 byte를 읽지만, nbyte에 못미치는 만큼의 글자만 들어올 수도 있다. 예를들어 파일의 끝에서는 buffer를 다 못채울만큼만 byte를 입력받을 확률이 높다.
만약 이런경우가 발생하더라도 read 함수는 정상적으로 작동했다고 본다.

#include <unistd.h>

write( )

file에 byte를 입력하기 위한 함수이다.
read함수와 거의 유사한 구조를 가지고 있다.
ssize_t write(int files, const void \*buf , size_t nbyte)
ssize_t : 입력하는데 성공한 byte return
*buf : buf의 byte들이 입력된다.
nbyte : 만큼의 byte를 입력한다. 보통은 buf와 같은 개수.

read()와 마찬가지로 요청한 모든 byte가 입력에 성공 하지 않을 수 있다. 이 경우 입력에 성공한 byte 수를 return하고 함수를 정상 종료한다.

#include <unistd.h>

close( )

open했던 file을 닫는 함수

  • process가 종료되면 자동으로 file은 닫힌다.
  • 하지만 process가 종료되지 않고 open된 file이 쌓이면 자원이 낭비 될 수 있다.

int close(int filedescriptor)
filedescriptor만 넘기면 바로 닫을 수 있다.
(error발생하면 -1을 return)

#include <unistd.h>

lseek( )

file의 현재 수정위치를 가리키는 "file offset"을 조종하는 함수

off_t lseek(int files, off_t offset, int start_flag)
filedes : 수정할 filedescriptor
offset : int 형태의 offset. offset의 위치를 얼마나 움직일지 정한다. 사용할때 (off_t)를 이용해 형변환을 해야한다.

start_flag : offset을 움직일때 그 기준을 설정하는 함수.

  • SEEK_SET : 파일 시작 지점
  • SEEK_CUR : 현재 offset의 위치
  • SEEK_END : 파일 끝

ex) lseek(fd, (off_t)-100, SEKK_END)
-> 파일 끝에서 뒤로 100byte만큼 offset을 움직인다.

#include <sys/types.h>
#include <unistd.h>

file pointer VS file descriptor

지금까지는 file descriptor을 이용해 파일을 지정하고 함수들을 다뤘는데 C에서 제공하는 상용 파일 입출력 함수(fprintf, fscanf 등)에서는 file pointer 이라는 포인터로 FILE자료형 이용해 file을 가리킨다.

이 차이에 대해 알아보자

file descriptor Table(FDT)

우리가 file을 열면(open()) file descriptor Table이라는 process의 table안에 그 정보가 저장된다. 이 table은 kernel의 System file table을 가리키고 있고, 여기에서는 open된 file의 정보들을 저장하고 있다.(offset, open option 등등)
그리고 이 System file table이 In-memorry inode table을 또 가리키고 있어 이를 통해 file에 접근 가능해진다.(inode table은 file 하나 당 하나만 열린다.)

따라서 그동안 우리가 open()의 return으로 받던 file descriptor은 file descriptor Table의 index였던 것이다.
(filedes가 int 형이었던 이유, STDIN_FILENO류의 실제 값이 0,1,2였던 이유이다.)

그럼 file pointer는 무엇일까
FILE이라는 자료형에는 file descriptor와 buffer가 들어있다. 이를 가리키는 포인터가 file pointer이었던 것이다.

FILE = file descriptor + Buffer

따라서 printf, fprintf류의 함수들은 line단위의 buffer를 가진다. 이곳에 값이 저장되어 있다가 입력된다.

0개의 댓글