제 4 장파일입출력 리눅스시스템프로그래밍 청주대학교전자공학과 한철수 1
시스템호출 (system call) 파일 (file) 임의접근 (random access) 주요학습내용 2
4.1 절 커널의역할 (kernel) 커널 (kernel) 은운영체제의핵심부분으로서, 하드웨어를운영관리하는여러가지서비스를제공함 파일관리 (File management) 디스크 프로세스관리 (Process management) CPU 메모리관리 (Memory management) 메모리 통신관리 (Communication management) 주변장치관리 (Device management) 주변장치 3
4.1 절 시스템호출 시스템호출 (system call) 이란운영체제가제공하는하드웨어관련서비스에대한프로그래밍인터페이스를말함 응용프로그램은시스템호출을통해서커널에하드웨어관련서비스를요청할수있음 4
4.1 절 시스템호출과정 5
4.1 절 주요시스템호출 주요자원 파일 (4~7 장 ) 프로세스 (8~9 장 ) 메모리 (10 장 ) 시그널 (11 장 ) 프로세스간통신 (12~13 장 ) 시스템호출 open(), close(), read(), write(), dup(), lseek() 등 fork(), exec(), exit(), wait(), getpid(), getppid() 등 malloc(), calloc(), free() 등 signal(), alarm(), kill(), sleep() 등 pipe(), socket() 등 6
파일 파일이란연속된바이트의나열을뜻함 디스크파일내의각바이트는주소를갖음 파일의사용절차 1. 파일열기 open() 시스템호출 2. 파일사용 read(), write() 시스템호출 3. 파일닫기 Close() 시스템호출 7
파일열기 : open() 파일을사용하기위해서는먼저 open() 시스템호출을이용하여파일을열어야함 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *path, int oflag, [ mode_t mode ]); 파일열기에성공하면파일디스크립터를, 실패하면 -1을반환함 파일디스크립터란열린파일을나타내는번호 (int 형 ) 로서, 이것을이용해파일의읽기, 쓰기, 닫기를할수있음 8
입출력방식지정 (oflag) int open (const char *path, int oflag, [ mode_t mode ]); O_RDONLY 읽기모드 O_WRONLY 쓰기모드 O_RDWR 읽기 / 쓰기모드 예 fd = open("account",o_rdonly); fd = open(argv[1], O_RDWR); 9
oflag 의다양한옵션 int open (const char *path, int oflag, [ mode_t mode ]); O_APPEND 데이터를쓰면파일끝에첨부됨 O_CREAT 해당파일이없는경우에생성함 mode 는생성할파일의사용권한을나타냄 O_TRUNC 파일이이미있는경우내용을지우고, 파일크기를 0 으로만듦 O_EXCL O_CREAT 와함께사용되며해당파일이이미있으면오류 O_NONBLOCK 넌블로킹모드로입출력하도록함 O_SYNC write() 시스템호출을하면디스크에물리적으로쓴후반환됨 10
파일열기의예 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) 11
파일닫기 : close() close() 시스템호출은 fd( 파일디스크립터 ) 가나타내는파일을닫음 #include <unistd.h> int close( int fd ); fd가나타내는파일을닫음성공하면 0, 실패하면 -1을반환함 12
fopen.c #include <stdio.h> #include <stdlib.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); 13
커맨드라인인수 커맨드라인에서프로그램을실행시키면서인수를전달할때사용함 커맨드라인인수를사용하지않을때 메인함수형태 : int main(void) 프로그램실행 : 파일명.exe 파일명 sample.exe sample 커맨드라인인수를사용할때 메인함수형태 : int main(int argc, char *argv[]) 프로그램실행 : 파일명.exe 인수파일명인수 1 인수 2 sample.exe abc sample 1 2 sample -w 14
커맨드라인인수예제 15
파일생성 : 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을반환함 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]); while( (nread = read(fd, buffer, BUFSIZE)) > 0) total += nread; close(fd); printf ("%s 파일크기 : %ld 바이트 \n", argv[1], total); exit(0); 18
데이터쓰기 : write() write() 시스템호출은 buf 에있는 nbytes 만큼의데이터를 fd 가나타내는파일에씀 #include <unistd.h> ssize_t write (int fd, void *buf, size_t nbytes); 파일에쓰기를성공하면실제쓰여진바이트수를반환하고, 실패하면 -1을반환함 19
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)) ==-1) { 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); 20
파일디스크립터복제 dup() 과 dup2() 호출은기존의파일디스크립터를복제함 #include <unistd.h> int dup(int oldfd); oldfd에대한복제본인새로운파일디스크립터를생성하여반환함 int dup2(int oldfd, int newfd); oldfd을 newfd에복제하고복제된새로운파일디스크립터를반환함실패하면 1을반환함 oldfd와복제된새로운디스크립터는하나의파일을공유함 oldfd 열린파일 newfd 21
dup.c #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> int main() { int fd, fd2; if((fd = creat("myfile", 0600)) == -1) perror("myfile"); write(fd, "Hello! Linux", 12); fd2 = dup(fd); write(fd2, "Bye! Linux", 10); exit(0); $./dup $ cat myfile Hello! LinuxBye! Linux 22
4.3 절 파일의임의접근 현재파일위치 (current file position) 파일내에서현재읽거나쓸위치 파일을열면현재파일위치는 0( 파일의시작 ) 이됨 파일에서데이터를읽거나, 데이터를쓰면현재파일위치는자동적으로읽거나쓴바이트수만큼앞으로이동함 파일위치포인터 (file position pointer) 현재파일위치 (current file position) 를가리키는포인터 23
4.3 절 파일위치포인터의이동 : lseek() lseek() 시스템호출 임의의위치로파일위치포인터를이동시킬수있음 #include <unistd.h> off_t lseek (int fd, off_t offset, int whence ); 이동에성공하면현재위치를반환하고, 실패하면 -1을반환함 SEEK_SET: 파일의시작점 SEEK_CUR: 현재파일위치 SEEK_END: 파일의끝 24
4.3 절 파일위치포인터의이동예 파일위치이동 lseek(fd, 0L, SEEK_SET); 파일시작으로이동 (rewind) lseek(fd, 100L, SEEK_SET); 파일시작에서 100 바이트위치로이동 lseek(fd, 0L, SEEK_END); 파일끝으로이동 (append) lseek(fd, -100L, SEEK_END); 파일끝에서 100 바이트뒤로이동 레코드단위로이동 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); 파일끝에서한레코드다음위치로이동 25
4.3 절 레코드저장예 write(fd, &record1, sizeof(record)); write(fd, &record2, sizeof(record)); lseek(fd, sizeof(record), SEEK_END); write(fd, &record3, sizeof(record)); 레코드 #1 레코드 #2 레코드 #3 26
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 rec; if (argc < 2) { fprintf(stderr, " 사용법 : %s file\n", argv[0]); exit(1); 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", &rec.id, rec.name, &rec.score) == 3) { lseek(fd, (rec.id - START_ID) * sizeof(rec), SEEK_SET); write(fd, &rec, sizeof(rec) ); close(fd); exit(0); 27
student.h #define MAX 24 #define START_ID 1401001 struct student { char name[max]; int id; int score; ; 28
dbquery.c (1) #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include "student.h" int main(int argc, char *argv[]) { char c; int fd, id; struct student rec; 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); 29
dbquery.c (2) do { printf("\n검색할학생의학번입력 :"); if (scanf("%d", &id) == 1) { lseek(fd, (id-start_id)*sizeof(rec), SEEK_SET); if ((read(fd, &rec, sizeof(rec)) > 0) && (rec.id!= 0)) printf(" 학번 :%d\t 이름 :%s\t 점수 :%d\n", rec.id, rec.name, rec.score); else printf(" 레코드 %d 없음 \n", id); else printf( 입력오류 ); printf(" 계속하겠습니까?(Y/N)"); scanf(" %c", &c); while (c=='y'); close(fd); exit(0); 30
4.3 절 레코드수정과정 1. 파일로부터해당레코드를읽음 2. 레코드를수정함 3. 수정된레코드를다시파일내의원래위치에써야함 31
dbupdate.c (1) #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 rec; 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); 32
dbupdate.c (2) do { printf(" 수정할학생의학번입력 : "); if (scanf("%d", &id) == 1) { lseek(fd, (long) (id-start_id)*sizeof(rec), SEEK_SET); if ((read(fd, &rec, sizeof(rec)) > 0) && (rec.id!= 0)) { printf(" 학번 :%8d\t 이름 :%4s\t 점수 :%4d\n", rec.id, rec.name, rec.score); printf(" 새로운점수 : "); scanf("%d", &rec.score); lseek(fd, (long) -sizeof(rec), SEEK_CUR); write(fd, &rec, sizeof(rec)); else printf(" 레코드 %d 없음 \n", id); else printf(" 입력오류 \n"); printf(" 계속하겠습니까?(Y/N)"); scanf(" %c",&c); while (c == 'Y'); close(fd); exit(0); 33
마무리 질문 Q&A 34