본문 바로가기
전공/유닉스

2장. 파일 입출력 (1)

by 임 낭 만 2023. 10. 5.

UNIX file 접근 primitives

  • file : byte들의 linear sequence
  • 파일 입출력
    • 저수준 파일 입출력 (open, close, read, write, dup, dup2, fcntl, lseek, fsync)
    • 고수준 파일 입출력 (fopen, fclose, fread, fwrite, fputs, fgets, fprintf, fscanf, freopen, fseek)

 

file descriptor

≒ 파일 포인터

  • 현재 open된 file을 구분할 목적으로 UNIX가 붙여 놓은 번호
  • 표준 입출력
    • 0 : 표준 입력
    • 1 : 표준 출력
    • 2 : 표준 오류 출력
  • 한 프로세스가 동시에 open 할 수 있는 file의 개수에는 제한이 있음.
    • close 사용 (close를 이용해 안 쓰는 파일은 닫아야함)

open 시스템 호출

  • 기존의 file을 open 하거나, 새롭게 file을 생성하여 open 하는 system call
  • 사용법 :
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *filename, int oflag, [mode_t mode]);
//두 번째 인수에 따라서 세번째 인수를 사용할수도 있고 하지 않을수도 있음
  • 인수 사용법
    • filename : 파일 이름
    • oflag : file을 access하는 방식
      • O_RDONLY 또는 O_WRONLY 또는 O_RDWR
        (파일이 존재했을 때 : 1. 파일을 읽기 2. 파일을 쓰기 가능 3. 파일 읽기, 쓰기 가능)
      • (만약 파일이 없으면 creat랑 파일 acces하는 방식, 총 두개를 사용)
        그리고, file을 create하는 방식
        O_CREAT 그리고 O_EXCL 또는 O_TRUNC
        (O_EXCL : 만약 파일이 존재하지 않는 경우에는 파일을 새로 만들어서 오픈을 할 건데, 만약 파일이 존재한다면 파일을 오픈하지 않을 것임. -> 오픈 실패)
        (O_TRUNC : 파일이 존재하면 기존에 있는 파일을 다 지우고 오픈)
      • 그리고, O_APPEND
        (파일을 오픈하자마자 파일 포인터를 파일의 가장 뒤로 가게 하는 것. 기존의 파일에 이어서 쓰고 싶을 때 사용)
    • mode : file을 새로 생성할때만 사용 (0600 또는 0664 또는 0644 또는 …)
      (첫 번째 숫자 : 내가 파일에 대해 어떠한 권한을 갖고 있는지, 두번째 숫자 : 나랑 같은 그룹의 사람들이 저 파일에 대해 어떤 권한을 갖고 있는지, 세번 째 숫자 : 그밖의 사람들이 파일에 대해 어떤 권한을 가지고 있는지 지정해주는 숫자)
      (읽기가 가능하게 설정하고 싶으면 4 + 쓰기가 가능하게 설정하고 싶으면 2 + 실행이 가능하게 설정하고 싶으면 1)
    • return 값 : 실행 성공 시 file descriptor (음이 아닌 정수); 실행 실패 시 -1
//맨처음 : 1-1파일은 없는 상태임. 1--2파일은 내용이 채워져있는 파일. 1-3파일 존재함.
int main(void) {
	int fd;
	
    	//읽기만 가능하게 오픈
	fd = open("data1-1", O_RDONLY);
	printf("#1 %d\n", fd);
	//1-1파일이 없으므로 명령 실패. 따라서 -1 출력
    
    	//쓰기 가능하게 오픈. 만약 파일이 없다면 만들어서 오픈하고 0600 커미션 붙이기
	fd = open("data1-1", O_WRONLY | O_CREAT, 0600);	
	printf("#2 %d\n", fd);
    	//1-1파일 만들어서 오픈됨. 첫 번째 오픈된 파일이므로 3출력

	//파일이 없으면 만들어서 오픈을 하고, 파일이 있으면 파일 오픈하지 않음
	fd = open("data1-1", O_WRONLY | O_CREAT | O_EXCL, 0600);
	printf("#3 %d\n", fd);
    	//1-1파일을 이미 만들었으므로, 실행 실패. 따라서 -1 출력

	//파일을 읽기 쓰기 가능하게 오픈할건데, 파일이 없으면 만들어서 오픈
    	//파일이 있으면 기존의 내용을 싹 지우고 오픈
	fd = open("data1-2", O_RDWR | O_CREAT | O_TRUNC, 0600);
	printf("#4 %d\n", fd);
    	//1-2파일의 내용이 모두 지워진 상태로 오픈됨. 4 출력

	//쓰기용으로 오픈하자마자 파일 포인터를 파일의 끝으로 옮김.
	fd = open("data1-3", O_WRONLY | O_APPEND);
	printf("#5 %d\n", fd);
    	//5 출력

	return 0;
}

creat 시스템 호출

  • file을 생성하여 open하거나, 기존 file을 open하는 system call
  • 사용법
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int creat(const char *filename, mode_t mode);
//첫 번째 인자 : 파일 이름, 두 번째 인자 : 모드
//파일이 있으면, 기존의 모드에 영향을 주지 않음.
  • 주의 사항 :
    • file을 쓰기 가능한 상태로 open
      (무조건 WRONLY로 오픈)
    • file이 이미 존재하면: 두 번째 인자는 무시; 기존 file은 0으로 open!
      (파일이 존재하면 파일의 내용을 다 지우고 오픈. open함수에서 O_CREAT|O_TRUNC 라고 봐도 무방)

 

close 시스템 호출

  • open 된 file을 close 할 때 사용
    • process 종료 시 open된 file들은 자동으로 close.
    • 그러나, 동시에 open할 수 있는 file 수 제한 때문에 close 사용
  • 사용법 :
#include <unistd.h>

int close(int filedes);
  • 인수 사용법 : 
    • filedes : open된 file의 file descriptor
    • return 값 : 성공 시 0; 실패 시 -1

 

read 시스템 호출

  • open된 file로부터 지정한 byte수 만큼의 data를 읽어 지정된 저장장소에 저장하는 명령
    • file pointer or read-write pointer : 읽혀질 다음 byte의 위치를 나타냄
  • 사용법 :
#include <unistd.h>

ssize_t read(int filedes, void *buffer, size_t nbytes);
//첫 번째 인자 : 파일의 번호
//두 번째 인자 : 파일에서 데이터를 읽어서 저장할 변수의 주소. 타입 상관 X (정수, 문자, 구조체..)
//세 번째 인자 : 바이트 숫자.
  • 인수 사용법 : 
    • filedes : open된 file의 file descriptor
    • *buffer : 읽은 data를 저장할 곳의 주소; data type은 상관 없음
    • nbytes : 읽을 byte 수; data type에 상관 없이 지정된 byte 수 만큼 읽음
    • return 값 : 성공 시, 실제 읽힌 byte 수; 실패 시, -1
      • return 값 < nbytes이면, file에 남은 data가 nbytes보다 적을 때
      • 그 다음은 더 이상 읽을게 없으면; return 값은 0
        (read를 할때마다 파일 포인터가 계속 움직임.)
        (읽기 실패 : file descriptor를 잘못 적었을때 즉, 파일이 없을때. 저장할 곳의 주소를 잘 못 적었을때. 저장할 곳이 없으면 실패)
//data2 파일 존재
int main(void) {
	char ch[100];
	int fd, n;

	fd = open("data2", O_RDONLY);
	n = read(fd, ch, 99); //99글자 읽기
	ch[n] = '\0';
	printf("fd=%d n=%d ch=%s", fd, n, ch);

	return 0;
}
//data3 파일 존재
int main(void) {
	int in[5], fd, i;

	fd = open("data3", O_RDONLY);
	for (i = 0; i < 5; i++) {
		read(fd, in + i, sizeof(int));
		printf("%d\n", in[i]);
	}

	return 0;
}
//data3존재함. 이 코드가 위보다 더 잘 짠 코드
int main(void) {
	int in[5], fd, i;

	fd = open("data3", O_RDONLY);
	read(fd, in, sizeof(int) * 5);
    	//한 번에 정수 다섯 개 읽음.
	for (i = 0; i < 5; i++) {
		printf("%d\n", in[i]);
	}

	return 0;
}

write 시스템 호출

  • 지정된 저장장소에서 지정한 byte수 만큼의 data를 읽어 open된 file에 쓰는 명령
    • file pointer or read-write pointer: 쓰여질 다음 byte의 위치를 나타냄
  • 사용법 :
#include <unistd.h>

ssize_t write(int filedes, const void *buffer, size_t nbytes);
  • 인수 사용법 :
    • filedes : write를 할 file의 descriptor
    • *buffer : write 할 내용이 들어 있는 저장 장소의 주소
    • nbytes : write할 byte의 수
    • return 값 : 쓰여진 byte 수 or -1
      • 보통은 return값 = n
      • return 값 < n이면, 쓰는 도중 media가 full
      • 만약, 쓰기 전에 꽉 차면 -1 return
  • 주의 사항
    • 기존 file을 open system call로 open하고 바로 write를 하면?
      (파일 포인터는 맨 처음으로 가게 됨. 따라서 바로 write를 하면 덮어쓰게 됨)
      (이를 원하지 않으면)
    • fd = open(“data”, O_WRONLY|O_APPEND);
      → open 하자마자, file pointer가 file의 끝으로 이동;
//data4는 존재하지 않음
int main(void) {
	char ch[100] = {};
	int fd, i;

	fd = open("data4", O_WRONLY | O_CREAT, 0600);
	for (i = 0; i < 3; i++) {
		scanf("%s", ch);
		write(fd, ch, strlen(ch));
	}

	return 0;
}
//data5는 존재하지 않음 -> 새로 만들 것임
int main(void) {
	int in[5], fd, i;

	fd = open("data5", O_WRONLY | O_CREAT, 0600);
	for (i = 0; i < 3; i++) {
		scanf("%d", &in[i]);
		write(fd, in + i, sizeof(int));
	}

	return 0;
}
//한꺼번에 write하는 방식
int main(void) {
	int in[5], fd, i;

	fd = open("data5", O_WRONLY | O_CREAT, 0600);
	for (i = 0; i < 3; i++) {
		scanf("%d", &in[i]);
	}
	write(fd, in, sizeof(int) * 5);

	return 0;
}

 

read/write의 효율성

  • File을 copy하는 프로그램의 실행 시간
    • BUFSIZE가 512 (disk blocking factor)의 배수 일 때, 효율적;
    • system call의 수가 적을수록 효율적

'전공 > 유닉스' 카테고리의 다른 글

6장. 프로세스 생성과 실행  (1) 2023.11.01
5장. 프로세스 정보  (0) 2023.11.01
4장. 시스템 정보  (0) 2023.11.01
3장. 파일과 디렉토리  (1) 2023.11.01
2장. 파일 입출력 (2)  (1) 2023.10.23

댓글