리눅스 상에서 사용가능한 파일 입출력 관련 시스템 콜을 소개한다. 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 |
댓글