열정 실천

File I/O System call - open(), read(), write(), close() 사용해서 cat, create 프로그램 만들어보기 본문

CS/운영체제

File I/O System call - open(), read(), write(), close() 사용해서 cat, create 프로그램 만들어보기

구운오니 2024. 9. 10. 20:23

 

시스템 콜 System call 이란? 

 

응용 프로그램과 운영체제 사이의 인터페이스이다. 

파일을 저장하고 불러오거나 프로세스를 관리를 위해 시스템을 호출하려면 유저모드가 아닌 커널모드에서만 작업을 수행해야한다. 우리가 주로 작성하는 c, java 등의 응용 프로그램들은 직접 시스템 호출을 할 수 없기 때문에 시스템 콜 API를 통해 커널모드를 통한 작업을 수행한다. 

 

*메모리에 상주하는 운영체제의 부분을 kernel(커널)이라고 한다. 

 

 

시스템 호출의 유형 5가지

 

1. 프로세스 제어 _ Process Control

2. 파일 조작 _ File Manipulation

3. 장치 조작 _ Device Manipulation

4. 정보 유지 보수 _ Information Maintance

5. 통신과 보호 _ Communication & Protection

 

이 중에 이번에 공부할 부분은 파일 조작 시스템 호출!!!!

 

 

File IO 시스템 콜

 

파일 관련 시스템 콜 API는 총 4가지가 있다. 

open(), read(), write(), close()

여기서 파일은 디스크에 저장되어 있다. 

 

 

 

  • 파일 열기 (open()):
    • 파일을 열 때, 운영 체제는 디스크에 있는 파일을 확인하고 파일의 메타데이터 (파일 크기, 위치, 권한 등) 정보를 가져온다. 
    • 파일이 성공적으로 열리면 파일 디스크립터(File Descriptor)가 반환된다.  (정상적으로 열리지 않으면 -1을 반환)
  • 파일 읽기 (read()):
    • read() 시스템 콜이 호출되면, 운영 체제는 파일의 데이터를 디스크에서 읽어들여, 프로그램이 접근할 수 있는 메모리(버퍼)에 로드한다. 
    • 이때 파일의 일부만 메모리로 읽어 올 수도 있고, 파일의 크기가 작으면 전체 파일이 한 번에 메모리로 로드될 수도 있다.
  • 파일 쓰기 (write()):
    • 파일에 데이터를 쓸 때, 운영체제는 지정된 파일 디스크립터를 참조하여 데이터를 먼저 메모리의 캐시 버퍼에 저장한다. 
    • 이후, 캐시에 저장된 데이터는 적절한 시점에 디스크로 기록된다. 

 

  • 파일 닫기 (close()):
    • 파일을 닫을 때, 운영체제는 열린 파일 디스크립터를 해제하고, 파일에 남아있는 버퍼 데이터를 디스크에 기록한다. 
    • 파일은 안전하게 닫히고, 프로그램은 해당 파일에 대한 자원을 반환받아 다른 작업에 사용할 수 있게 된다. 

 

 

 

 

✨ 각각 API의 파라미터에 대해 더 자세하게 알아보자!! ✨

 

 

 

 

📃 open(pathname, flags, mode)

 

- pathname : 열고자하는 파일의 경로
- flags : 파일의 권한 옵션 
- mode : 파일이 새로 생성될 때, 해당 파일의 권한을 설정

 

권한 옵션 

 

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

O_CREAT : 파일 생성
O_EXCL : 파일이 존재할 시 -1 반환

 

 

📃 read(fd, buf, count)

 

- fd : 읽을 파일의 파일 디스크립터로 파일을 참조
- buf : 데이터를 저장할 메모리 버퍼 
- count : 한 번에 읽고자 하는 데이터의 바이트 크기 

 

 

📃 write(fd, buf, count)

 

- fd : 쓸 파일의 파일 디스크립터로 파일을 참조

- buf : 데이터를 저장한 메모리 버퍼. 이 버퍼에 있는 데이터를 파일에 쓴다. 

- count : 한 번에 쓰고자 하는 데이터의 바이트 크기 

 

 

📃 close(fd)

 

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

 

 

 

 

🎊 위의 파일 syscall을 사용해서 리눅스 명령어 cat 프로그램을 직접 만들어보자!! 🎊

 

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

#define MAX_BUF 64

int main(int argc, char *argv[]){
        int fd, read_size, write_size;
        char buf[MAX_BUF];

        if(argc!=2) { //if문에서 인자의 수가 두 개가 아니면 에러메세지를 출력한다.
                printf("USAGE: %s file_name\n",argv[0]);
                exit(-1);
        }
        
        //argv[0] : ./mycat
        //argv[1] : 파일 명
        
        fd = open(argv[1], O_RDONLY); //open() 함수로 argv[1]을 읽기 전용 옵션으로 불러온다.
        
        if(fd < 0) {  //fd가 음수이면 파일을 불러오지 못한 것이므로 에러메세지를 출력한다. 
                printf("Can't open %s file with errno %d\n", argv[1], errno);
                exit(-1);
                /*open error handling*/
        }
        
        
        //while문을 통해 파일 안의 있는 값을 한 번에 64바이트씩 읽어들여 표준 출력에 출력한다. 
        while(1){
                read_size = read(fd,buf,MAX_BUF);
                if(read_size==0){
                        break;
                }
                write_size=write(STDOUT_FILENO,buf,read_size);
        }

        close(fd); //파일을 닫아준다. 


}

컴파일 후 mycat 실행!!

 

 

 

 

 

 

🎊 새로운 파일을 생성하는 프로그램을 만들어보자!! 🎊

mycreat.c

 

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

#define MAX_BUF 64

/* $./mycreat.c 파일명*/

int main(int argc, char *argv[]){
        int fd, read_size, write_size;
        char buf[MAX_BUF];

        //O_RDWR : 읽기,쓰기가 가능한 옵션
        //O_CREAT : 파일을 생성하는 옵션
        //O_EXCL : 파일이 존재할 시 -1을 반환하는 옵션 
        
        fd = open(argv[1],O_RDWR | O_CREAT | O_EXCL, 0664);
        if(fd < 0) {
                printf("Can't open %s file with errno %d\n", argv[1], errno);
                exit(1);
                /*open error handling*/
        }

        write_size=write(fd,argv[2], sizeof(argv[2]));
        printf("File name: %s\n",argv[1]);
        printf("Enter the data: %d", argv[2]);
        close(fd);

        fd=open(argv[1],O_RDONLY);

        /*읽은 데이터 바이트 수 -MAX_BUF이거나 마지막 부분이라면 그 이하*/
        read_size = read(fd,buf,MAX_BUF);


        close(fd);

}