Download presentation
Presentation is loading. Please wait.
1
4장 파일
2
4.1 시스템 호출
3
컴퓨터 시스템 구조 유닉스 커널(kernel) 하드웨어를 운영 관리하여 다음과 같은 서비스를 제공
파일 관리(File management) 프로세스 관리(Process management) 메모리 관리(Memory management) 통신 관리(Communication management) 주변장치 관리(Device management)
4
시스템 호출 시스템 호출은 커널에 서비스 요청을 위한 프로그래밍 인터페이스
응용 프로그램은 시스템 호출을 통해서 커널에 서비스를 요청한다.
5
시스템 호출 과정
6
시스템 호출 요약 주요 자원 시스템 호출 파일 open(), close(), read(), write(), dup(), lseek() 등 프로세스 fork(), exec(), exit(), wait(), getpid(), getppid() 등 메모리* malloc(), calloc(), free() 등 시그널 signal(), alarm(), kill(), sleep() 등 프로세스 간 통신 pipe(), socket() 등
7
4.2 파일
8
유닉스에서 파일 연속된 바이트의 나열 특별한 다른 포맷을 정하지 않음 디스크 파일뿐만 아니라 외부 장치에 대한 인터페이스
9
파일 열기: open() 파일을 사용하기 위해서는 먼저 open() 시스템 호출을 이용하 여 파일을 열어야 한다.
파일 디스크립터는 열린 파일을 나타내는 번호이다. #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *path, int oflag, [ mode_t mode ]); 파일 열기에 성공하면 파일 디스크립터를, 실패하면 -1을 리턴
10
파일 열기: open() oflag O_RDONLY 읽기 모드, read() 호출은 사용 가능 O_WRONLY
쓰기 모드, write() 호출은 사용 가능 O_RDWR 읽기/쓰기 모드, read(), write() 호출 사용 가능 O_APPEND 데이터를 쓰면 파일끝에 첨부된다. O_CREAT 해당 파일이 없는 경우에 생성하며 mode는 생성할 파일의 사용권한을 나타낸다.
11
파일 열기: open() oflag O_TRUNC 파일이 이미 있는 경우 내용을 지운다. O_EXCL
O_CREAT와 함께 사용되며 해당 파일이 이미 있으면 오류 O_NONBLOCK 넌블로킹 모드로 입출력 하도록 한다. O_SYNC write() 시스템 호출을 하면 디스크에 물리적으로 쓴 후 반환된다
12
파일 열기: 예 fd = open("account",O_RDONLY); fd = open(argv[1], O_RDWR);
fd = open(argv[1], O_RDWR | O_CREAT, 0600); fd = open("tmpfile", O_WRONLY|O_CREAT|O_TRUNC, 0600); fd = open("/sys/log", O_WRONLY|O_APPEND|O_CREAT, 0600); if ((fd = open("tmpfile", O_WRONLY|O_CREAT|O_EXCL, 0666))==-1)
13
fopen.c #include <stdio.h> #include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h> int main(int argc, char *argv[]) { int fd; if ((fd = open(argv[1], O_RDWR)) == -1) perror(argv[1]); printf("파일 %s 열기 성공\n", argv[1]); close(fd); exit(0); }
14
파일 생성: creat() creat() 시스템 호출 path가 나타내는 파일을 생성하고 쓰기 전용으로 연다.
생성된 파일의 사용권한은 mode로 정한다. 기존 파일이 있는 경우에는 그 내용을 삭제하고 연다. 다음 시스템 호출과 동일 open(path, WRONLY | O_CREAT | O_TRUNC, mode); #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat (const char *path, mode_t mode ); 파일 생성에 성공하면 파일 디스크립터를, 실패하면 -1을 리턴
15
파일 닫기: close() close() 시스템 호출은 fd가 나타내는 파일을 닫는다.
#include <unistd.h> int close( int fd ); fd가 나타내는 파일을 닫는다. 성공하면 0, 실패하면 -1을 리턴한다.
16
데이터 읽기: read() read() 시스템 호출 fd가 나타내는 파일에서 nbytes 만큼의 데이터를 읽고
읽은 데이터는 buf에 저장한다. #include <unistd.h> ssize_t read ( int fd, void *buf, size_t nbytes ); 파일 읽기에 성공하면 읽은 바이트 수, 파일 끝을 만나면 0, 실패하면 -1을 리턴
17
fsize.c #include <stdio.h> #include <unistd.h> #include <fcntl.h> #define BUFSIZE 512 /* 파일 크기를 계산 한다 */ int main(int argc, char *argv[]) { char buffer[BUFSIZE]; int fd; ssize_t nread; long total = 0; if ((fd = open(argv[1], O_RDONLY)) == -1) perror(argv[1]);
18
fsize.c /* 파일의 끝에 도달할 때까지 반복해서 읽으면서 파일 크기 계산 */ while( (nread = read(fd, buffer, BUFSIZE)) > 0) total += nread; close(fd); printf ("%s 파일 크기 : %ld 바이트 \n", argv[1], total); exit(0); }
19
데이터 쓰기: write() write() 시스템 호출 buf에 있는 nbytes 만큼의 데이터를 fd가 나타내는 파일에 쓴다
#include <unistd.h> ssize_t write (int fd, void *buf, size_t nbytes); 파일에 쓰기를 성공하면 실제 쓰여진 바이트 수를 리턴하고, 실패하면 -1을 리턴
20
copy.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> /* 파일 복사 프로그램 */ main(int argc, char *argv[]) { int fd1, fd2, n; char buf[BUFSIZ]; if (argc != 3) { fprintf(stderr,"사용법: %s file1 file2\n", argv[0]); exit(1); } if ((fd1 = open(argv[1], O_RDONLY)) == ) { perror(argv[1]); exit(2); } if ((fd2 =open(argv[2], O_WRONLY | O_CREAT|O_TRUNC 0644)) == -1) { perror(argv[2]); exit(3); while ((n = read(fd1, buf, BUFSIZ)) > 0) write(fd2, buf, n); // 읽은 내용을 쓴다. exit(0);
21
파일 디스크립터 복제 dup()/dup2() 호출은 기존의 파일 디스크립터를 복제한다.
oldfd와 복제된 새로운 디스크립터는 하나의 파일을 공유한다. #include <unistd.h> int dup(int oldfd); oldfd에 대한 복제본인 새로운 파일 디스크립터를 생성하여 반환하다. 실패하면 –1을 반환한다. int dup2(int oldfd, int newfd); oldfd을 newfd에 복제하고 복제된 새로운 파일 디스크립터를 반환한다.
22
파일 디스크립터 복제 oldfd 열린 파일 newfd
23
dup.c 1 #include <unistd.h> 2 #include <fcntl.h>
3 #include <stdlib.h> 4 #include <stdio.h> 6 int main() 7 { 8 int fd, fd2; 9 10 if((fd = creat("myfile", 0600)) == -1) perror("myfile"); 12 13 write(fd, "Hello! Linux", 12); 14 fd2 = dup(fd); 15 write(fd2, "Bye! Linux", 10); 16 exit(0); 17 } $ dup $ cat myfile Hello! LinuxBye! Linux
24
4.3 임의 접근 파일
25
파일 위치 포인터(file position pointer)
파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일 위 치(current file position)를 가리킨다.
26
파일 위치 포인터 이동: lseek() lseek() 시스템 호출 임의의 위치로 파일 위치 포인터를 이동시킬 수 있다.
#include <unistd.h> off_t lseek (int fd, off_t offset, int whence ); 이동에 성공하면 현재 위치를 리턴하고 실패하면 -1을 리턴한다.
27
파일 위치 포인터이동: 예 파일 위치 이동 레코드 단위로 이동 파일끝 이후로 이동
lseek(fd, 0L, SEEK_SET); 파일 시작으로 이동(rewind) lseek(fd, 100L, SEEK_SET); 파일 시작에서 100바이트 위치로 lseek(fd, 0L, SEEK_END); 파일 끝으로 이동(append) 레코드 단위로 이동 lseek(fd, n * sizeof(record), SEEK_SET); n+1번째 레코드 시작위치로 lseek(fd, sizeof(record), SEEK_CUR); 다음 레코드 시작위치로 lseek(fd, -sizeof(record), SEEK_CUR); 전 레코드 시작위치로 . 파일끝 이후로 이동 lseek(fd, sizeof(record), SEEK_END); 파일끝에서 한 레코드 다음 위치로
28
레코드 저장 예 write(fd, &record1, sizeof(record));
lseek(fd, sizeof(record), SEEK_END); write(fd, &record3, sizeof(record)); 레코드 #1 레코드 #2 레코드 #3
29
dbcreate.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include "student.h" /* 학생 정보를 입력받아 데이터베이스 파일에 저장한다. */ int main(int argc, char *argv[]) { int fd; struct student record; if (argc < 2) { fprintf(stderr, "사용법 : %s file\n", argv[0]); exit(1); }
30
dbcreate.c if ((fd = open(argv[1], O_WRONLY|O_CREAT|O_EXCL, 0640)) == -1) { perror(argv[1]); exit(2); } printf("%-9s %-8s %-4s\n", "학번", "이름", "점수"); while (scanf("%d %s %d", &record.id, record.name, &record.score) == 3) { lseek(fd, (record.id - START_ID) * sizeof(record), SEEK_SET); write(fd, (char *) &record, sizeof(record) ); close(fd); exit(0);
31
student.h #define MAX 24 #define START_ID 1401001 struct student {
char name[MAX]; int id; int score; };
32
dbquery.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include "student.h" /* 학번을 입력받아 해당 학생의 레코드를 파일에서 읽어 출력한다. */ int main(int argc, char *argv[]) { int fd, id; struct student record; if (argc < 2) { fprintf(stderr, "사용법 : %s file\n", argv[0]); exit(1); } if ((fd = open(argv[1], O_RDONLY)) == -1) { perror(argv[1]); exit(2);
33
dbquery.c do { printf("\n검색할 학생의 학번 입력:"); if (scanf("%d", &id) == 1) { lseek(fd, (id-START_ID)*sizeof(record), SEEK_SET); if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0)) printf("이름:%s\t 학번:%d\t 점수:%d\n", record.name, record.id, record.score); else printf("레코드 %d 없음\n", id); } else printf(“입력 오류”); printf("계속하겠습니까?(Y/N)"); scanf(" %c", &c); } while (c=='Y'); close(fd); exit(0); }
34
레코드 수정 과정 (1) 파일로부터 해당 레코드를 읽어서 (2) 이 레코드를 수정한 후에
(3) 수정된 레코드를 다시 파일 내의 원래 위치에 써야 한다.
35
레코드 수정
36
dbupdate.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include "student.h" /* 학번을 입력받아 해당 학생 레코드를 수정한다. */ int main(int argc, char *argv[]) { int fd, id; char c; struct student record; if (argc < 2) { fprintf(stderr, "사용법 : %s file\n", argv[0]); exit(1); } if ((fd = open(argv[1], O_RDWR)) == -1) { perror(argv[1]); exit(2);
37
dbupdate.c do { printf("수정할 학생의 학번 입력: "); if (scanf("%d", &id) == 1) { lseek(fd, (long) (id-START_ID)*sizeof(record), SEEK_SET); if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0)) { printf("학번:%8d\t 이름:%4s\t 점수:%4d\n", record.id, record.name, record.score); printf("새로운 점수: "); scanf("%d", &record.score); lseek(fd, (long) -sizeof(record), SEEK_CUR); write(fd, (char *) &record, sizeof(record)); } else printf("레코드 %d 없음\n", id); } else printf("입력오류\n"); printf("계속하겠습니까?(Y/N)"); scanf(" %c",&c); } while (c == 'Y'); close(fd); exit(0); }
38
핵심 개념 시스템 호출은 커널에 서비스를 요청하기 위한 프로그래밍 인 터페이스로 응용 프로그램은 시스템 호출을 통해서 커널에 서 비스를 요청할 수 있다. 파일 디스크립터는 열린 파일을 나타낸다. open() 시스템 호출을 파일을 열고 열린 파일의 파일 디스크립 터를 반환한다. read() 시스템 호출은 지정된 파일에서 원하는 만큼의 데이터 를 읽고 write() 시스템 호출은 지정된 파일에 원하는 만큼의 데이터를 쓴다. 파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일 위 치를 가리킨다. lseek() 시스템 호출은 지정된 파일의 현재 파일 위치를 원하는 위치로 이동시킨다.
Similar presentations