제 2 장. 파일입출력 (File I/O) 숙대창병모 1
목표 파일의구조및특성을이해한다. 파일을열고닫는다. 파일로부터데이터를읽고쓴다. 파일현재위치변경 기타파일제어 숙대창병모 2
2.1 파일구조 숙대창병모 3
What is a file? a file is a contiguous sequence of bytes no format imposed by the operating system each byte is individually addressable in a disk file a file is also a uniform interface to external devices 숙대창병모 4
File Descriptor File descriptor open() returns a fd, an integer value 열린파일을나타내는번호 used in subsequent I/O operations on that file close(fd) closes that file described by fd all of a process's open files are automatically closed when it terminates 숙대창병모 5
File Descriptor file descriptor : 0 ~ 19 Value Meaning 0 standard input 1 standard output 2 standard error 3.. 19 fds for users 숙대창병모 6
User and Kernel Mode User process result=open( /usr/glass/file.txt, O_RDONLY); User code Kernel Address of kernel close() Address of kernel open() Address of kernel write() open(char *name, int mode) { <Place parameters in registers> <Execute trap instruction, switching to kernel code > <Return result of system call> } C runtime library kernel code for open() { <Manipulate kernel data> 숙대창병모 7... <Return to user code> } Kernel system call code
Inode (Index node) 한파일은하나의 i-node 를갖는다. 파일에대한모든정보를가지고있음 file type : regular, directory, block special, character special, etc file size file permissions the owner and group ids the last modification and last access times if it's a regular or directory, the location of data blocks if it's a special file, device numbers if it's a symbolic link, the value of the symbolic link 숙대창병모 8
파일을위한커널자료구조 fd= open( file, O_RDONLY); Fd table (per process) Open file table Active inode table Disk 0 1 2 3 File pos refcnt=1 File access Inode list... File size File type Data blocks... 숙대창병모 9
Process table entry 프로세스테이블 (Process table) 커널 (kernel) 자료구조 프로세스목록 프로세스 프로세스테이블항목 프로세스테이블항목 (Process table entry) 파일디스크립터배열 (file descriptor array) 포함 fd array 숙대창병모 10
Open File Table 파일테이블 (file table) 커널자료구조 열려진모든파일목록 열려진파일 파일테이블의항목 파일테이블항목 (file table entry) 파일상태플래그 (read, write, append, sync, nonblocking, ) 파일의현재위치 (current file offset) i-node에대한포인터 숙대창병모 11
Active i-node table Active i-node table 커널내의자료구조 Open 된파일들의 i-node 를저장하는테이블 i-node 하드디스크에저장되어있는파일에대한자료구조 한파일에하나의 i-node 하나의파일에대한정보저장 소유자, 크기 파일이위치한장치 파일내용디스크블럭에대한포인터 i-node table vs. i-node 숙대창병모 12
2.2 파일관련시스템호출 open() - 열기 creat() - 파일생성 close() - 닫기 read() - 읽기 write() - 쓰기 lseek() - 이동 숙대창병모 13
open() - 열기 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *pathname, int oflag, [ mode_t mode ]); 파일을연다 파일이없으면경우에따라새로만들어질수도있다 리턴값 : 파일디스크립터 (file descriptor), 실패하면 -1 pathname : 파일의이름 mode : 파일의 access permission 값. 생략가능. 새로운파일을만드는경우에만사용됨 creat() 함수설명참조 숙대창병모 14
open() 의파라미터 두번째파라미터 oflag 는다음상수들의 OR 이다 예 int fd; fd = open("afile", O_RDWR O_CREAT, 0600 ); 반드시하나지정해주어야할값 O_RDONLY : 읽기모드, write 함수를사용할수없음 O_WRONLY : 쓰기모드, read 함수를사용할수없음 O_RDWR : 읽고쓰기모드, read write 사용가능 숙대창병모 15
open() 의파라미터 선택적지정가능 O_APPEND: 모든 write 된데이터는파일의끝에추가 O_CREAT : 파일이없는경우파일생성세번째인자 mode O_EXCL : O_CREAT 이고그파일이이미있으면에러 O_TRUNC : 파일이있는경우파일크기를 0 으로만든다 O_NONBLOCK : nonblocking 모드로입출력을함 O_SYNC : 각 write 함수호출은디스크에물리적으로쓰여진후리턴한다 숙대창병모 16
예제 : open.c /* open.c */ #include <stdlib.h> #include <fcntl.h> #include <unistd.h> int main() { int fd; char fname[] = "afile"; } if ((fd = open (fname, O_RDWR)) == -1) perror(fname); printf("%s is opened.\n", fname); close(fd); return 0; 숙대창병모 17
creat () - 파일생성 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat ( const char *pathname, mode_t mode ); 새로운파일을생성한다 리턴값 : 파일디스크립터, 실패하면 -1 pathname : 생성하고자하는파일의이름 mode : 파일의 access permission 값 숙대창병모 18
creat () 의파라미터 두함수호출은동일 fd = creat ( pathname, mode ); fd = open ( pathname, O_WRONLY O_CREAT O_TRUNC, mode); 두번째인자 mode 는 permission mode 예 0644 0777 0444 숙대창병모 19
close () - 닫기 #include <unistd.h> int close ( int fd ); 작업이끝난후파일을닫는다. 리턴값 : 성공하면 0, 실패하면 -1 fd : 닫고자하는파일의파일디스크립터 프로세스가종료되면모든열려진화일들은자동적으로닫힌다 숙대창병모 20
read () - 읽기 #include <unistd.h> ssize_t read ( int fd, void *buf, size_t nbytes ); fd가나타내는파일에서데이터를읽는다 리턴값 : buf 성공하면읽은바이트수 파일의끝을만나면 0 실패하면 -1 읽은데이터를저장할메모리의시작주소 nbytes 읽을데이터의바이트수 숙대창병모 21
read () - 읽기 읽을데이터가충분하면한번에 nbytes 만큼읽는다. 읽을데이터가 nbytes 보다적으면더적게읽는다. 파일의끝에서 네트웍입출력에서 size_t : unsigned integer ssize_t : signed integer 숙대창병모 22
예제 /* count.c: 파일의문자수를센다 */ #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #define BUFSIZE 512 int main() { char buffer[bufsize]; int fd; ssize_t nread; long total = 0; } if ((fd = open("afile", O_RDONLY)) == -1) perror("afile"); /* 파일의끝에도달할때까지반복 */ while( (nread = read(fd, buffer, BUFSIZE)) > 0) total += nread; close(fd); printf ("total chars in afile: %ld\n", total); return 0; 숙대창병모 23
write() - 쓰기 #include <unistd.h> ssize_t write (int fd, void *buf, size_t nbytes); fd가나타내는파일에데이터를쓴다 리턴값 buf 성공하면, 파일에쓰여진데이터의바이트수 실패하면, -1 쓸데이터를저장하고있는메모리의시작주소 nbytes 쓸데이터의바이트의수 숙대창병모 24
예 : Copy Files #include <stdio.h> #include <fcntl.h> main(argc, argv) int argc; char *argv[ ]; { int fdin, fdout, n; char buf[bufsize]; if (argc!= 3) { fprintf(stderr,"usage: %s filein fileout\n",argv[0]); exit(1); } if ((fdin = open(argv[1], O_RDONLY)) == -1) { perror(argv[1]); exit(2); } if ((fdout=open(argv[2],o_wronly O_CREAT O_TRUNC, 0644))==-1){ perror(argv[2]); exit(3);} } while ((n = read(fdin, buf, BUFSIZE)) > 0) write(fdout, buf, n); exit(0); 숙대창병모 25
lseek() - 이동 #include <sys/types.h> #include <unistd.h> off_t lseek (int fd, off_t offset, int whence ); 파일의현재위치 (current file offset) 를이동 성공하면현재위치를리턴, 실패하면 -1 whence : 위치기준점 SEEK_SET : 파일의시작점을기준으로이동 SEEK_CUR : 현재위치를기준으로이동 SEEK_END : 파일의끝을기준으로이동 offset : 기준점에서의상대적인거리 (byte 단위 ) SEEK_CUR, SEEK_END 와같이쓰일때는음수도가능 숙대창병모 26
lseek() 이동 파일의현재위치 (current file offset) 파일을처음열면현재위치는 0 즉파일의시작 파일에대한읽기 / 쓰기는파일의현재위치에서실행된다 읽기 / 쓰기후파일의현재위치는읽기 / 쓰기한 byte 수만큼자동적으로뒤로이동 lseek() 임의의위치로파일의현재위치를이동할수있다 숙대창병모 27
예 :lseek rewind append lseek(fd, 0L, 0); lseek(fd, 0L, 2); record position loc = lseek(fd, 0L, 1); increase file lseek(fd, (long) MAX*sizeof(record), 2); write(fd, (char *) &reocrd, sizeof(record)); 숙대창병모 28
예제 : /* lseek.c */ #include <unistd.h> int main() { if (lseek(stdin_fileno, 0, SEEK_CUR) == -1) printf("cannot seek\n"); else printf("seek OK\n"); return 0; } 숙대창병모 29
예제 : /* lseek1.c */ #include <unistd.h> /* lseek1.c */ #include <fcntl.h> char char buf1[] = "abcdefghij"; buf2[] = "ABCDEFGHIJ"; int main() { int fd; } if ( (fd = creat("file.hole", 0644)) < 0) perror("file.hole"); if (write(fd, buf1, 10)!= 10) /* offset now = 10 */ perror("buf1"); if (lseek(fd, 40, SEEK_SET) == -1) /* offset now = 40 */ perror("lseek"); if (write(fd, buf2, 10)!= 10) /* offset now = 50 */ perror("buf2"); return 0; 숙대창병모 30
예제 : /* lseek1.c */ lseek1.c 의출력파일 file.hole 의내용 0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j 10 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 20 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 30 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 40 A B C D E F G H I J 숙대창병모 31
예제 : /* lseek2.c */ #include <sys/types.h> /* lseek2.c */ #include <unistd.h> #include <fcntl.h> int main() { int fd; off_t fsize; char buf[11]; } if((fd=open("file.hole", O_RDONLY)) < 0) perror("file.hole"); fsize = lseek(fd, 0, SEEK_END); printf("size: %lu\n", fsize); lseek(fd, 40, SEEK_SET); read(fd, buf, 10); buf[10] = \0 ; puts(buf); return 0; 숙대창병모 32
레코드수정 struct XXX record; read(fd, (char *) &record, sizeof(record)); update record lseek(fd, (long) -sizeof(record), 1); write(fd, (char *) &record, sizeof(record)); 숙대창병모 33
레코드수정 record READ current file offset 숙대창병모 34
레코드수정 record LSEEK current file offset 숙대창병모 35
레코드수정 record WRITE current file offset 숙대창병모 36
2.3 시스템호출구현 숙대창병모 37
Block I/O I/O is always done in terms of blocks Sequence of a read() system call read() system call trap n bytes the device driver (software in kernel) I/O request one block at a time interrupt the disk controller (hardware) 숙대창병모 38
A Typical Hardware System CPU chip register file ALU system bus memory bus bus interface I/O bridge main memory USB controller graphics adapter I/O bus disk controller Expansion slots for other devices such as network adapters. mousekeyboard monitor disk 숙대창병모 39
Reading a Disk Sector: Step 1 CPU chip register file ALU CPU initiates a disk read by writing a command, logical block number, and destination memory address to a port (address) associated with disk controller. bus interface main memory I/O bus USB controller graphics adapter disk controller mousekeyboard monitor disk 숙대창병모 40
Reading a Disk Sector: Step 2 CPU chip register file ALU Disk controller reads the sector and performs a direct memory access (DMA) transfer into main memory. bus interface main memory I/O bus USB controller graphics adapter disk controller mousekeyboard monitor disk 숙대창병모 41
Reading a Disk Sector: Step 3 CPU chip register file ALU When the DMA transfer completes, the disk controller notifies the CPU with an interrupt (i.e., asserts a special interrupt pin on the CPU) bus interface main memory I/O bus USB controller graphics adapter disk controller mousekeyboard monitor disk 숙대창병모 42
I/O 효율 디스크는메모리에비해서매우느린장치 성능을위해서디스크 I/O의횟수최소화가바람직 적은양을여러번 I/O 하는것보다 많은양을 I/O 하여횟수를줄이는것이좋다 write1.c 에서 BUFFSIZE 값을변경하며수행시간을 측정 8192 까지는 BUFFSIZE 가클수록성능이향상 8192 보다큰경우는성능에변화가없다 숙대창병모 43
I/O 효율 BSD fast file system 의 I/O 단위는 8192 바이트 BUFSIZE 가 8192 보다큰경우 내부 I/O 의단위는 8192 이므로성능의향상이없다 BUFSIZE 가 8192 의배수가아닌경우는 오히려 8192 인경우보다 I/O 횟수가많아져 성능이하락할수있다 숙대창병모 44
예제 : /* write1.c */ #include <sys/types.h> /* write1.c */ #include <sys/stat.h> #include <fcntl.h> #define BUFFSIZE 512 #define FILESIZE (100 * 1024 * 1024) #define COUNT FILESIZE / BUFFSIZE int main() { int i, fd; char buf[buffsize]; } memset(buf, '.', BUFFSIZE); if ((fd = creat("file.write", 0600)) < 0) perror("file.write"); for (i=0; i < COUNT; ++i) write(fd, buf, BUFFSIZE); close(fd); return 0; 숙대창병모 45
숙대창병모 46 800 3.6 1.1 0.0 131,072 1,600 3.6 1.1 0.0 65,536 3,200 3.6 1.1 0.0 32,768 6,400 3.6 1.1 0.0 16,384 12,800 3.6 1.1 0.0 8,192 25,600 4.2 1.6 0.0 4,096 51,200 4.7 2.0 0.0 2,048 102,400 6.0 2.9 0.1 1,024 204,800 7.9 4.9 0.3 512 409,600 10.4 7.4 0.5 256 819,200 16.3 12.8 1.1 128 1,638,400 28.1 23.5 2.0 64 3,276,800 51.6 45.1 3.9 32 6,553,600 98.1 86.7 8.5 16 13,107,200 191.5 172.3 16.6 8 26,214,400 379.6 343.9 31.6 4 52,428,800 764.5 681.1 73.3 2 104,857,600 1,527.8 1,378.1 140.9 1 #loops Clock time (seconds) System CPU (seconds) User CPU (seconds) BUFFSIZE 예제 : /* write1.c */
read/write 구현 read/write 시스템호출 file table entry 의 file position 값이읽은 / 쓰여진바이트수만큼증가 파일크기증가 Write 후 file position 이 i-node 의 file size 보다크면파일크기증가 파일을 O_APPEND 로열면 먼저 file position 을 i-node 의 file size 값으로설정한후 write 수행 따라서모든 write 는파일의끝에덧붙여진다. 숙대창병모 47
read/write 시스템호출구현 Fd table (per process) Open file table Active inode table Disk 0 1 2 3 File pos refcnt=1 File access Inode list... File size File type Data blocks... 숙대창병모 48
Example read(fd, buf1, 100); copy the first block from disk into an buffer copy the first 100 bytes from the buffer into buf1 offset <- 100 read(fd, buf2, 200); copy the next 200 bytes from the buffer into buf2 read(fd, buf3, 5000); copy the remaning (3796bytes) from the buffer to buf3 copy the second block from disk into an buffer copy the remainig(1204 bytes) from the buffer into buf3 write(fd, buf4, 100); write(fd, buf5, 4000); 숙대창병모 49
lseek 구현 lseek 시스템호출 file table entry 의 current file offset 값을변경 disk I/O 는없음 SEEK_END 를사용하여파일의끝으로이동하면 file table entry 의 current file offset 값은 i-node 의파일크기값으로설정됨 숙대창병모 50
lseek 구현 lseek(fd, 300, L_SET) Fd table (per process) Open file table Active inode table Disk 0 1 2 3 File pos=300 refcnt=1 File access Inode list... File size File type Data blocks... 숙대창병모 51
2.4 파일공유 숙대창병모 52
dup(), dup2() #include <unistd.h> int dup (int fd); int dup2 (int fd, int fd2); 사용중인파일디스크립터의복사본을만듦 dup() 는새파일디스크립터번호가할당됨 dup2() 는 fd2 를사용 리턴값 성공하면복사된새파일디스크립터, 실패하면 -1 dup() 함수는할당가능한가장작은번호를리턴한다. dup2() 함수는 fd2 를리턴한다. 숙대창병모 53
dup 구현 fd2 = dup(3); Fd table (per process) Open file table Active inode table Disk 0 1 Inode list 2 3 4 File pos=300 refcnt=2 File access... File size File type Data blocks... 숙대창병모 54
dup 구현 fd2 = dup(3); Fd table (per process) Open file table Active inode table Disk 0 1 Inode list 2 3 4 File pos=300 refcnt=2 File access... File size File type Data blocks... 숙대창병모 55
#include <fcntl.h> #include <unistd.h> int main() { int fd1, fd2, n; char buf[11]; } 예제 /* dup.c */ if ((fd1 = open("afile", O_RDONLY)) < 0) perror("afile"); if ((fd2 = dup(fd1)) < 0) error("dup"); n = read(fd1, buf, 10); buf[n] = \0 ; puts(buf); n = read(fd2, buf, 10); buf[n] = \0 ; puts(buf); close(fd1); close(fd2); return 0; 숙대창병모 56
dup2() newfd = dup2(3,1); 호출후 리턴값은 1 file table 의 file position 과 fd status flags 는공유됨 file descriptors 의 fd flags 는공유안됨 숙대창병모 57
dup2(3,1) 구현 Fd table (per process) Open file table Active inode table Disk 0 1 2 3 4 File pos refcnt=1... File pos refcnt=1 File access File size File type... File access File size File type... Inode list Data blocks... 숙대창병모 58
dup2(3,1) 구현 Fd table (per process) Open file table Active inode table Disk 0 1 2 3 4 File pos refcnt=1... File pos refcnt=1 File access File size File type... File access File size File type... Inode list Data blocks... 숙대창병모 59
dup(), dup2() 의용도 표준입출력의 redirection 표준입출력대상을파일로바꿈 표준입출력의파일디스크립터 #include <unistd.h> #define STDIN_FILENO 0 /* 표준입력 */ #define STDOUT_FILENO 1 /* 표준출력 */ #define STDERR_FILENO 2 /* 표준에러 */ 숙대창병모 60
예제 : /* dup1.c */ #include <unistd.h> #include <fcntl.h> #include <stdio.h> int main() { int fd; } if((fd = creat("afile", 0600)) == -1) perror("afile"); printf("this is displayed on the screen.\n"); dup2(fd, STDOUT_FILENO); printf("this is written into the redirected file.\n"); return 0; 숙대창병모 61
예제 : /* dup2.c */ #include <unistd.h> #include <fcntl.h> #include <stdio.h> int main() { int fd; } if((fd = creat("afile", 0600)) == -1) perror("afile"); printf("this is displayed on the screen.\n"); close(stdout_fileno); dup(fd); printf("this is written into the redirected file.\n"); return 0; 숙대창병모 62
open() 두번 같은파일두번 open( file, O_RDONLY); file position 은공유되지않는다 Fd table (per process) Open file table Active inode table Disk 0 1 Inode list 2 3 4 File pos refcnt=1... File access File pos File size File type... Data blocks refcnt=1... 숙대창병모 63
예제 /* open2.c */ #include <fcntl.h> /* open2.c */ #include <unistd.h> int main() { int fd1, fd2, n; char buf[11]; fd1 = open("afile", O_RDONLY); fd2 = open("afile", O_RDONLY); if (fd1 < 0 fd2 < 0) perror("afile"); n = read(fd1, buf, 10); buf[n] = \0 ; puts(buf); n = read(fd2, buf, 10); buf[n] = \0 ; puts(buf); } close(fd1); close(fd2); return 0; 숙대창병모 64
두프로세스에서같은파일 open() Fd table(per process) Open 0 file table 1 2 3 File pos 4 refcnt=2 Active inode table Disk Inode list... File access 0 1 2 3 4 File pos refcnt=2... File size File type... Data blocks 숙대창병모 65
fork() 0 1 2 3 4 Fd table (per process) Open file table File pos Active inode table Disk Inode list refcnt=2 File access 0 1 2 3 4... File size File type... Data blocks 숙대창병모 66