[Linux] 파일 입출력 System call 함수

FDT, FT, IT

- FDT(파일디스크립터 테이블) : 프로세스마다 한개씩 가지고있음. 0:stdin, 1:stdout, 2:stderr로 자동할당, 3부터 파일 open시 할당된다. 파일을 시스템 프로그래밍 차원에서 바이트단위의 입출력으로 다룰 수 있게 한다.

FT(파일 테이블) : 모든 프로세서가 오픈한 파일에 대한 참조. 파일디스크립터 테이블에서 참조하는 수

- IT(아이노드 테이블)

 

open(2)

파일을 열거나 생성할 때 사용하는 system call 함수

#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
int open(const char* pathname, int oflag);
int open(const char* pathname, int oflag, mode_t mode);

@param pathname: 열거나 생성할 파일명(경로)

@param oflag: open할 파일의 특성 결정. 어떤 용도로 사용할지 결정

@param mode: 파일의 읽기/쓰기/실행 권한을 지정

@return: 파일에 대한 올바른 접근인지 확인한 후 파일 디스크립터 리턴

 

파일 접근 모드 플래그

O_RDONLY / O_WRONLY / O_RDWR : 파일을 읽기/쓰기/읽고쓰기 전체의 권한으로 오픈 > 셋 중 하나 사용가능
O_APPEND : 파일에 IO시 오프셋을 자동으로 파일 맨 끝으로 이동 (내용 추가)
O_CREAT : 파일이 존재하지 않을 경우 생성
O_EXCL : CREAT옵션과 함께 사용, 파일이 이미 존재하면 에러 리턴
O_TRUNC : 파일이 이미 존재할 경우 덮어쓰기

 

 

 

 

 

creat()

파일 생성시 사용하는 시스템 호출함수. 다만 open함수에 O_CREAT 옵션을 주면 되기때문에 잘 사용하지는 않는다.

#include<sys/stat.h>
#include<sys./types.h>
#include<fcntl.h>
int creat(const char* pathname, mode_t mode);

 

상태 플래그를 사용하지 않는다는 점만 제외하면 open(2)과 동일하다. 

open(pathname, O_WRONLY|O_CREAT|O_TRUNC, mode);
open(pathname, O_RDWR|O_CREAT|O_TRUNC, mode);

쓰기 기능이 들어가도록("w"나 "w+") 상태플래그를 주면 된다. 

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

int main() {
	
	char* fname = "ssu_test.txt";
	int fd;

	if((fd=creat(fname, 0666))<0) {
		fprintf(stderr, "creat error for %s\n", fname);
		exit(1);
	}
	else {
		printf("Success!\nFilename : %s\nDescripter : %d\n", fname, fd);
		close(fd);
	}

	exit(0);
}

> creat()함수를 통해서 파일을 열고 디스크립터를 출력하는 예제.

creat의 mode값으로 0666이 들어간것은 rw-rw-rw-을 의미한다. (4-2-1) 

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

int main() {

	char* fname = "ssu_test.txt";
	int fd;

	if((fd = creat(fname, 0666))<0) {
		fprintf(stderr, "creat error for %s\n", fname);
		exit(1);
	}
	else {
		close(fd);
		fd = open(fname, O_RDWR);
		printf("Succeeded!\n<%s> is new readable and writable\n", fname);
	}

	exit(0);
}

> close()했다가 다시 open해도 문제가 발생하지 않는다. (단지 새로운 파일디스크립터값을 할당받을것임)

 

 

 

 

lseek()

파일을 오픈한 뒤 offset의 위치를 명시적으로 변경하는 시스템 호출함수이다. offset의 위치만 변경하고 리턴해줄 뿐 I/O는 일어나지 않는다.

#include<sys/types.h>
#include<unistd.h>
off_t lseek(int filedes, off_t offset, int whence);

@param filedes: 대상 파일 디스크립터 번호

@param offset: 변경할 바이트 수

@param whence: 기준 오프셋 (SEEK_SET, SEEK_CUR, SEEK_END)

@return off_t: 정수(integer)형. 새 파일 오프셋을 리턴한다. 정규 파일이 아닌경우 lseek이 불가하므로 -1을 리턴한다.

SEEK_SET : 파일의 오프셋 위치를 파일의 처음으로 지정. 처음부터 입출력을 하려면 offset인자를 0으로 지정해주면 됨
SEEK_CUR : 파일의 오프셋 위치를 현재 오프셋 위치에 offset인자만큼 더한 값으로 설정. 현재 오프셋 위치를 알려면 offset인자를 0으로 지정해주면 됨
SEEK_END : 파일의 오프셋 위치를 파일 크기 다음으로 지정. 파일의 끝에 새로운 데이터를 추가하려고 하면 이 값과 함께 offset인자를 0으로 지정하면 됨

 

 

ㆍ파일 오프셋(offset)이란 파일의 어느 부분을 읽는지를 의미한다. 오프셋 값은 O_APPEND 상태 플래그가 적용되어 있으면 파일의 끝, 적용되어 있지 않으면 항상 0을 기본값으로 갖는다. 

ㆍ오프셋이 파일의 실제 크기보다 클 경우, 그만큼 파일의 크기가 증가한다. 

 

 

 

예제

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>

int main() {

	char* fname = "ssu_test.txt";
	off_t fsize;
	int fd;

	if((fd = open(fname, O_RDONLY))<0) {
		fprintf(stderr, "open error for %s\n", fname);
		exit(1);
	}

	if((fsize = lseek(fd,(off_t)0,SEEK_END)) < 0) {
		fprintf(stderr, "lseek error\n");
		exit(1);
	}

	printf("The size of <%s> is %ld bytes.\n", fname, fsize);
	exit(0);

}

> lseek함수과 SEEK_END를 통해서 파일의 바이트 수를 구하는 예제

 

 

 

 

 

 

 

read()

open상태의 파일에서 데이터를 읽을 때 사용하는 시스템 호출함수. 읽기 전용("r") 혹은 읽기쓰기모드("r+")로 오픈된 파일로부터 지정된 메모리로 nbytes만큼의 데이터를 읽음

#include<unistd.h>
ssize_t read(int filedes, void* buf, size_t nbytes);

@param filedes: 오픈된 파일 디스크립터

@param buf: 파일을 읽어들일 버퍼

@param nbytes: 읽을 메모리 바이트수

@return: 실제로 읽은 바이트 수(integer)(파일의 끝을 읽을 경우 중단되기 때문에 요청한 바이트 nbytes보다 작을 수 있음), 파일의 오프셋 위치도 읽은 바이트수만큼 이동된다.