본문 바로가기
Study/System Programming

open, read, write, close 사용하기

by 개발새-발 2021. 11. 15.
반응형

리눅스 상에서 사용가능한 파일 입출력 관련 시스템 콜을 소개한다. open, read, write, close는 c를 처음 배울 때 사용하던 파일 관련 함수인 fopen, fread, fwrite와 유사하고, 이들은 사실 이 시스템 콜을 사용한다.

open

파일 경로와 flag, mode를 입력으로 넣어주면 file descriptor를 전달하여 준다. fcntl.h 헤더에 포함되어 있다.

#include <fcntl.h>

int open (const char *name, int flags)
int open (const char *name, int flags, mode_t mode)
  • open
    • 인자
      • const char* name : 파일의 절대 경로 혹은 상대 경로이거나 파일 이름이다.
      • int flags : 반드시 O_RDONLY , O_WRONLY, O_RDWR 값들 중 하나이어야 한다. 각각 "읽기 전용", "쓰기 전용", "읽기 쓰기"를 나타낸다. 몇 가지 다른 값들과 or 연산을 통하여 같이 사용할 수 있다.
      • mode_t mode : flags에 O_CREAT가 포함되어있는 경우 새로 만들어지는 파일의 권한을 설정한다.

flags

위에서 언급하였듯이 O_RDONLY , O_WRONLY, O_RDWR 값 중 하나이어야 하고 각각 "읽기 전용", "쓰기 전용", "읽기 쓰기"를 나타낸다. OR 연산을 통해서 다른 값들과 같이 사용할 수 있다. 예를 들어 쓰기 전용으로 열고, name으로 주어진 경로 혹은 이름의 파일이 존재하지 않을 때는 그 파일을 생성하고 싶을 때 O_WRONLY | O_CREAT를 사용하여 주면 된다. 아래는 같이 사용할 수 있는 flag의 예제이다.

  • O_CREAT : 파일이 존재하지 않는 경우 새로 파일을 생성한다.
  • O_EXCL : O_CREAT를 사용하였는데 이미 파일이 존재하는 않은 경우 open이 fail 한다.
  • O_APPEND : write 할 때 파일의 맨 뒤에서 수행한다.
  • O_TRUNC : O_WRONLY, O_RDWR과 같이 쓰였을 때 파일이 이미 존재하는 경우 내용을 전부 지우고 새로 쓴다.

mode

O_CREAT로 생성되는 파일의 권한을 설정한다. 0600처럼 8진수 값을 넣어도 되고, 혹은 S_IRWXU (0700) 와 S_IRUSR (0400)과 같은 정의되어있는 상수를 바로 사용하거나 or로 섞어서 써도 된다. 관련 상수는 open(2)와 관련된 man page에서 O_CREAT 이하의 내용에서 볼 수 있다.

read

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
  • read
    • 인자
      • int fd : file descriptor이다. open의 반환 값이나 stdin, stdout, stderr 에 해당하는 0, 1, 2를 넣어주면 된다.
      • void* buf : 읽어올 결과물을 받을 버퍼이다.
      • size_t count : 읽어올 결과물의 길이이다.
    • 반환 값
      • read에 성공한 byte의 수이다.
      • EOF 인경우 0이다.
      • read에 실패한 경우 -1을 반환하고 errno를 설정한다.

write

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
  • write
    • 인자
      • int fd : file descriptor이다. open의 반환 값이나 stdin, stdout, stderr 에 해당하는 0,1,2를 넣어주면 된다.
      • const void* buf : write 할 값이 담긴 buffer이다.
      • size_t count : write할 내용의 길이이다.
    • 반환 값
      • write에 성공한 byte의 수이다.
      • write에 실패한 경우 -1을 반환하고 errno를 설정한다.

open read write 예제

example 1

아래와 같은 파일이 하나 존재한다. 이 파일의 이름은 a_text_file.txt이다. 이 파일을 읽은 후 출력해보겠다.

text line 1
textline2_and_there_is_more
oh third line hoho
a is apple
b is banana
c is charlie
d is delta
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 200

int main(void){
    ssize_t ret;
    char buf[BUF_SIZE]={0,};

    int fd = open("a_text_file.txt",O_RDONLY);

    read(fd,buf,BUF_SIZE-1);
    printf("%s\n",buf);

    close(fd);
}

아래는 실행 결과이다.

$ ./read1
text line 1
textline2_and_there_is_more
oh third line hoho
a is apple
b is banana
c is charlie
d is delta

$ 

example 2

파일이 매우 크면 원하는 버퍼 하나에 파일 내용을 전부 담을 수 없다. 특정 바이트 수만큼 읽고, 출력을 반복하여 파일 전체의 내용을 출력하도록 하자.

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 11

int main(void){
    int fd = open("a_text_file.txt",O_RDWR);

    ssize_t ret;
    char buf[BUF_SIZE]={0,};

    while(ret = read(fd,buf,BUF_SIZE-1)){
        buf[ret] = 0;
        printf("%s",buf);
    }

    close(fd);
}
$ ./read2
text line 1
textline2_and_there_is_more
oh third line hoho
a is apple
b is banana
c is charlie
d is delta
$ 

example 3

open에서 O_CREAT로 파일을 생성해본다.
현재 이 폴더에는 newfile.txt 파일이 존재하지 않는다.

$ ls
a.out  a_text_file.txt  file_to_write.txt  file_to_write2.txt  fileio1.md  open1.c  read1  read1.c  read2  read2.c  write1.c  write2.c

아래 코드를 컴파일하고 실행하면 newfile.txt 파일이 생성될까?

#include <fcntl.h>
#include <unistd.h>

int main(void){
    int fd = open("newfile.txt",O_RDWR|O_CREAT);

    write(fd,"file",4);
}

확인 결과 파일이 생성되었고, 내용이 입력되어있는 것을 볼 수 있다.

$ ls
a.out  a_text_file.txt  file_to_write.txt  file_to_write2.txt  fileio1.md  newfile.txt  open1.c  read1  read1.c  read2  read2.c  write1.c  write2.c
$ cat newfile.txt
file

example 4

example 2를 수정하여 printf가 아닌 write를 사용하여 출력해보자. write의 file descriptor를 입력하는 부분에 stdout에 해당하는 숫자를 입력하면 된다.

#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 10

int main(void){
    int fd = open("a_text_file.txt",O_RDONLY);

    ssize_t ret;
    char buf[BUF_SIZE]={0,};

    while(ret = read(fd,buf,BUF_SIZE)){
        write(STDOUT_FILENO,buf,ret);
    }

    close(fd);
}

example 5

프로그램 실행 시에 두 파일의 이름을 받아서 첫 번째 파일의 내용을 두 번째 파일에 복사하도록 하겠다. linux의 cp 명령어를 생각하면 된다.

#include <fcntl.h>
#include <unistd.h>

#define BUF_SIZE 20

int main(int argc,char** argv){
    if(argc < 3){
        return -1;
    }

    char* file_path_from = argv[1];
    char* file_path_to = argv[2];

    char buffer[BUF_SIZE];

    int fd_from = open(file_path_from,O_RDONLY);
    int fd_to = open(file_path_to,O_WRONLY|O_CREAT|O_TRUNC,0700);
    int ret=0;

    if(fd_from == -1 || fd_to == -1){
        return -1;
    }

    while(ret=read(fd_from,buffer,BUF_SIZE)){
        write(fd_to,buffer,ret);
    }
}

위 코드를 컴파일한 결과인 mycp로 파일 복사를 수행한 후 내용을 보자.

$ ./mycp a_text_file.txt copy_text_file.txt
$ cat copy_text_file.txt
text line 1
textline2_and_there_is_more
oh third line hoho
a is apple
b is banana
c is charlie
d is delta

복사가 된 것을 볼 수 있다.

반응형

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

lseek, pread, pwrite 사용하기  (0) 2021.11.17
wait, waitpid의 사용  (0) 2021.10.19
fork 사용하기  (0) 2021.10.17
sigprocmask을 사용하여 signal block 하기  (0) 2021.10.16

댓글