Linux 환경에서 파일 입출력을 다루는 방법에는 두 가지가 있다. 하나는 저수준 파일 입출력이고 다른 하나는 고수준 파일 입출력이다.
저수준 파일 입출력은 시스템의 커널에서 제공하는 system call 함수를 사용하는 방법이다. 리눅스에서는 예시로 open, read, write 등등이 있다. 당연히 system call 함수를 이용하기 때문에 고수준 파일 입출력보다 더 빠른 파일 처리가 가능하다. 저수준 파일 입출력의 특징중 하나는 "바이트" 단위로 파일을 다룬다는 것이다. 그렇기 때문에 일반 파일뿐 아니라 특수 파일까지 다룰 수 있다. 여기서 특수 파일은 데이터 전송이나 디바이스 접근에서 사용하는 파일을 말한다. 마지막으로 파일을 다룰 때 handler인 파일 디스크립터를 사용한다.
고수준 파일 입출력은 fopen, fread, fputs와 같은 표준 입출력 라이브러리를 사용하는 방법이다. 이 방법은 바이트 단위로 입출력하는 저수준 파일 입출력과 달리 버퍼를 이용하여 한번에 파일을 읽고 쓸 수 있다. 고수준 파일 입출력함수는 저수준 파일 입출력을 이용하여 만들어진다. 그렇기 때문에 저수준 파일 입출력이 고수준 파일 입출력보다 빠르다.
저수준 파일 입출력에서 사용하는 파일 디스크립터는 프로세스가 실행될때 각 프로세스마다 가지고 있는 파일 디스크립터 테이블에 할당되게 된다. 파일 디스크립터 테이블은 파일 디스크립터의 목록을 관리하는 자료구조이다. 파일 디스크립터 테이블에는 현재 이 프로세스에서 오픈한 파일의 목록들을 알 수 있다. 파일 디스크립터 값은 정수형인 integer 값이다. 이 값은 파일 디스크립터에게 부여된 번호이다. 프로세스가 생성될 경우 0, 1, 2번 파일 디스크립터는 자동적으로 할당되게 된다. 0번은 표준입력(STDIN), 1번은 표준출력(STDOUT), 2번은 표준 에러를 나타낸다. 따라서 프로세스가 생성될 경우 시스템에서 파일 디스크립터 테이블에 자동으로 0, 1, 2번을 할당한다. 그 다음 프로그래머가 직접 파일을 열 경우 3번부터 순서대로 할해당 파일에 접근할 수 있는 파일 디스크립터가 부여되게 된다.
고수준 파일 입출력에서는 파일 포인터를 사용한다. fopen의 리턴값인 FILE형 구조체 변수를 가리키는 포인터를 통해 파일에 접근할 수 있다. FILE 구조체에는 오픈한 파일을 처리할 수 있는 정보가 기록된다. 당연히 fopen을 통해 파일을 열어도 파일 디스크립터는 생성이 된다. 파일 포인터로부터 파일 디스크립터를 알고 싶다면 fileno(FILE*)라는 함수를 통해 파일포인터에 해당하는 파일디스크립터를 얻을 수 있다. 파일 포인터 구조체는 다음과 같다.
typedef struct {
int cnt; //버퍼에 남은 문자 수
unsigned char *base; //버퍼 시작 주소
unsigned char *ptr //버퍼의 현재 포인터 주소
unsigned flag //파일의 접근 권한
int fd; //파일 디스크립터
} FILE;
대표적인 저수준 파일 입출력 함수와 고수준 파일 입출력 함수를 이용하여 간단한 예제를 실행해 보겠다. 아래는 파일을 열고 읽고 쓰는데 필요한 시스템 호출 함수와 표준 입출력 함수이다.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
//저수준 파일 입출력
char fdbuffer[10];
int fd = open("file.txt", O_RDWR);
read(fd, fdbuffer, 10);
write(STDOUT_FILENO, fdbuffer, 10);
close(fd);
printf("\n");
//고수준 파일 입출력
char fpbuffer[10];
FILE* fp = fopen("file.txt", "r+");
fread(fpbuffer, 10, 1, fp);
fwrite(fpbuffer, 10, 1, stdout);
fclose(fp);
}
위 코드는 file.txt라는 파일이 있을 때 저수준 파일 입출력 방법과 고수준 파일 입출력 방법으로 각각 10바이트를 읽어와 화면에 출력하는 함수이다. 실행 결과는 다음과 같다
file.txt파일에는 I'm shyeon이라는 길이 10의 문자열이 들어있다. 이때 위의 코드로 파일 디스크립터와 파일 포인터를 이용해 읽어올 경우 위와 같이 나타나게 된다.
'리눅스 시스템 프로그래밍' 카테고리의 다른 글
[Linux] Mutex를 이용하여 스레드(Thread) 동기화하기 (0) | 2021.08.11 |
---|---|
[Linux] 리눅스 시스템 프로그래밍 thread(스레드) 생성과 종료 (0) | 2021.08.06 |
[Linux] Bash shell script programming 2021년도 요일 구하기 (0) | 2021.07.19 |
[Linux] Bash shell script programming 소수 합 구하기 (0) | 2021.07.19 |
[Linux] Bash shell 환경 변수와 지역 변수 (0) | 2021.07.19 |