파일 기술자 복사 파일 기술자 복사 : dup(2) 파일 기술자 복사 : dup2(3) 기존 파일 기술자를 인자로 받아 새로운 파일 기술자를 리턴 새로운 파일 기술자는 현재 할당할 수 있는 파일 기술자 중 가장 작은 값으로 자동 할당 파일 기술자 복사 : dup2(3) 새로운 파일 기술자를 지정할 수 있다. #include <unistd.h> int dup(int fildes); #include <unistd.h> int dup2(int fildes, int fildes2);
[예제 2-7] 파일 기술자 복사하기 ex2_7.c 01 #include <fcntl.h> [예제 2-7] 파일 기술자 복사하기 ex2_7.c 01 #include <fcntl.h> 02 #include <unistd.h> 03 #include <stdlib.h> 04 #include <stdio.h> 05 06 int main(void) { 07 int fd, fd1; 08 09 fd = open("tmp.aaa", O_CREAT | O_WRONLY | O_TRUNC, 0644); 10 if (fd == -1) { 11 perror("Create tmp.aaa"); 12 exit(1); 13 } 14 15 close(1); 16 17 fd1 = dup(fd); 18 19 printf("DUP FD=%d\n", fd1); 20 printf("Standard Output Redirection\n"); 21 close(fd); 22 23 return 0; 24 } 표준출력(1)을 닫았다 fd를 복사하면 가장 작은 값인 1로 복사 표준출력을 출력한 내용이 파일로 저장 # ex2_7.out # cat tmp.aaa DUP FD=1 Standard Output Redirection
[예제 2-8] dup2 함수 사용하기 01 #include <fcntl.h> ex2_8.c 01 #include <fcntl.h> 02 #include <unistd.h> 03 #include <stdlib.h> 04 #include <stdio.h> 05 06 int main(void) { 07 int fd; 08 09 fd = open("tmp.bbb", O_CREAT | O_WRONLY | O_TRUNC, 0644); 10 if (fd == -1) { 11 perror("Create tmp.bbb"); 12 exit(1); 13 } 14 15 dup2(fd, 1); 16 17 printf("DUP2 : Standard Output Redirection\n"); 18 close(fd); 19 20 return 0; 21 } 표준출력(1)로 지정하여 복사 표준출력을 출력한 내용이 파일로 저장된다. # ex2_8.out # cat tmp.bbb DUP2 : Standard Output Redirection
표준 입력, 표준 출력 및 표준 오류 표준 입력(0), 표준 출력(1), 표준 오류(2) redirection < > prog_name < infile prog_name > outputfile pipe prog1 | prog2
표준 입출력 01 #include <fcntl.h> 02 #include <unistd.h> ex2_8.c 01 #include <fcntl.h> 02 #include <unistd.h> 03 #include <stdlib.h> 04 #include <stdio.h> 05 #define SIZE 512 06 int main(void) { 07 ssize_t nread; 08 char buf[SIZE] 09 10 while ((nread = read(0, buf, SIZE)) > 0 11 write(1, buf, nread); 12 13 return 0; 14 }
실습 위 프로그램을 수정하여 명령줄 인수가 있는지 조사하고, 만일 인수가 존 재하면, 각 인수를 하나의 파일 이름으로 취급하고 각 파일의 내용을 표 준 출력으로 복사하는 프로그램을 작성하라. 만일 명령 줄 인수가 존재하 지 않으면, 입력을 표준 입력으로부터 받아야 한다.
test1.c를 참고하여 예제 2-9에서 open flag를 확인하는 기능을 추가할 것 파일 기술자 제어 파일 기술자 제어 : fcntl(2) 파일 기술자가 가리키는 파일에 cmd로 지정한 명령을 수행 cmd의 종류에 따라 인자(arg)를 지정할 수 있음 자주 사용하는 cmd #include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fcntl(int fildes, int cmd, /* arg */ ...); test1.c를 참고하여 예제 2-9에서 open flag를 확인하는 기능을 추가할 것
[예제 2-9] fcntl 함수로 파일 기술자 제어하기 ex2_9.c 07 int main(void) { 08 int fd, flags; 09 10 fd = open("unix.txt", O_RDWR); 11 if (fd == -1) { 12 perror("open"); 13 exit(1); 14 } 15 16 if ((flags = fcntl(fd, F_GETFL)) == -1) { 17 perror("fcntl"); 18 exit(1); 19 } 20 21 flags |= O_APPEND; 22 23 if (fcntl(fd, F_SETFL, flags) == -1) { 24 perror("fcntl"); 25 exit(1); 26 } 27 28 if (write(fd, "Hanbit Media", 12) != 12) perror("write"); 29 close(fd); 30 31 return 0; 32 } 파일을 추가 모드로 수정 # cat unix.txt Unix System Programming # ex2_9.out Hanbit Media 파일에 내용 추가
파일 삭제 unlink(2) remove(3) #include <unistd.h> path에 지정한 파일의 inode에서 링크 수를 감소시킨다. 링크 수가 0이 되면 path에 지정한 파일이 삭제된다. 파일 뿐만 아니라 디렉토리(빈 디렉토리 아니어도 됨)도 삭제된다. remove(3) path에 지정한 파일이나 디렉토리를 삭제한다. 디렉토리인 경우 빈 디렉토리만 삭제한다. #include <unistd.h> int unlink(const char *path); #include <stdio.h> int remove(const char *path);
Inode 구조
[예제 2-10] unlink 함수로 파일 삭제하기 ex2_10.c 01 #include <unistd.h> 02 #include <stdlib.h> 03 #include <stdio.h> 04 05 int main(void) { 06 int cnt; 07 08 cnt = unlink("tmp.aaa"); 09 if (cnt == -1) { 10 perror("Unlink tmp.aaa"); 11 exit(1); 12 } 13 14 printf("Unlink tmp.aaa success!!!\n"); 15 16 return 0; 17 } tmp.aaa 파일 삭제 # ls -l tmp* -rw-r--r-- 1 root other 37 1월 6일 17:50 tmp.aaa -rw-r--r-- 1 root other 35 1월 6일 18:06 tmp.bbb # ex2_10.out Unlink tmp.aaa success!!!
파일 포인터 고수준 파일 입출력 : 표준 입출력 라이브러리 파일 포인터 고수준 파일 입출력에서 열린 파일을 가리키는 포인터 자료형으로 FILE * 형을 사용 -> 구조체에 대한 포인터
파일 열기와 닫기[1] 파일 열기: fopen(3) #include <stdio.h> filename으로 지정한 파일을 mode로 지정한 모드에 따라 열고 파일 포인터를 리턴 mode 값 #include <stdio.h> FILE *fopen(const char *filename, const char *mode); FILE *fp; fp = fopen("unix.txt", "r");
파일 열기와 닫기[2] 파일 닫기: fclose(3) #include <stdio.h> fopen으로 오픈한 파일을 닫는다. #include <stdio.h> int fclose(FILE *stream); FILE *fp; fp = fopen("unix.txt", "r"); fclose(fp);
문자 기반 입력함수: fgetc(3), getc(3), getchar(3), getw(3) 문자 기반 입출력 함수 문자 기반 입력함수: fgetc(3), getc(3), getchar(3), getw(3) fgetc : 문자 한 개를 unsigned char 형태로 읽어온다. getc, getchar : 매크로 getw : 워드 단위로 읽어온다. 문자 기반 출력함수: fputc(3), putc(3), putchar(3), putw(3) #include <stdio.h> int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void); int getw(FILE *stream); #include <stdio.h> int fputc(int c, *stream); int putc(int c, *stream); int putchar(int c); int putw(int w, FILE *stream);
EOF를 만날 때까지 한 문자씩 읽어서 파일로 출력 [예제 2-11] 문자 기반 입출력 함수 사용하기 ex2_11.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 int main(void) { 05 FILE *rfp, *wfp; 06 int c; 07 08 if ((rfp = fopen("unix.txt", "r")) == NULL) { 09 perror("fopen: unix.txt"); 10 exit(1); 11 } 12 13 if ((wfp = fopen("unix.out", "w")) == NULL) { 14 perror("fopen: unix.out"); 15 exit(1); 16 } 17 18 while ((c = fgetc(rfp)) != EOF) { 19 fputc(c, wfp); 20 } 21 22 fclose(rfp); 23 fclose(wfp); 24 25 return 0; 26 } EOF를 만날 때까지 한 문자씩 읽어서 파일로 출력 # cat unix.txt Unix System Programming # ex2_11.out # cat unix.out
문자열 기반 입력 함수: gets(3), fgets(3) 문자열 기반 입출력 문자열 기반 입력 함수: gets(3), fgets(3) gets : 표준 입력에서 문자열을 읽어들인다. fgets : 파일(stream)에서 n보다 하나 적게 문자열을 읽어 s에 저장 문자열 기반 출력 함수: puts(3), fputs(3) #include <stdio.h> char *gets(char *s); char *fgets(char *s, int n, FILE *stream); #include <stdio.h> char *puts(const char *s); char *fputs(const char *s, FILE *stream);
[예제 2-12] 문자열 기반 입출력 함수 사용하기 # ex2_12.out # cat unix.out ex2_12.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 int main(void) { 05 FILE *rfp, *wfp; 06 char buf[BUFSIZ]; 07 08 if ((rfp = fopen("unix.txt", "r")) == NULL) { 09 perror("fopen: unix.txt"); 10 exit(1); 11 } 12 13 if ((wfp = fopen("unix.out", "a")) == NULL) { 14 perror("fopen: unix.out"); 15 exit(1); 16 } 17 18 while (fgets(buf, BUFSIZ, rfp) != NULL) { 19 fputs(buf, wfp); 20 } 21 22 fclose(rfp); 23 fclose(wfp); 24 25 return 0; 26 } 한 행씩 buf로 읽어서 파일로 출력 # ex2_12.out # cat unix.out Unix System Programming
[예제 2-13] fread 함수로 파일 읽기 # ex2_13.out n=3, buf=Unix S n=3, buf=ystem ex2_13.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 int main(void) { 05 FILE *rfp; 06 char buf[BUFSIZ]; 07 int n; 08 09 if ((rfp = fopen("unix.txt", "r")) == NULL) { 10 perror("fopen: unix.txt"); 11 exit(1); 12 } 13 14 while ((n=fread(buf, sizeof(char)*2, 3, rfp)) > 0) { 15 buf[6] = '\0'; 16 printf("n=%d, buf=%s\n", n, buf); 17 } 18 19 fclose(rfp); 20 21 return 0; 22 } # ex2_13.out n=3, buf=Unix S n=3, buf=ystem n=3, buf=Progra n=3, buf=mming
버퍼 기반 입출력 버퍼 기반 입력함수: fread(3) 버퍼 기반 출력함수: fwrite(3) 항목의 크기가 size인 데이터를 nitems에 지정한 개수만큼 읽어 ptr에 저장 성공하면 읽어온 항목 수를 리턴 읽을 항목이 없으면 0을 리턴 버퍼 기반 출력함수: fwrite(3) 항목의 크기가 size인 데이터를 nitems에서 지정한 개수만큼 ptr에서 읽어서 stream으로 지정한 파일에 출력 성공하면 출력한 항목의 수를 리턴 오류가 발생하면 EOF를 리턴 #include <stdio.h> size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream); #include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
[예제 2-14] fwrite 함수로 파일 출력하기 ex2_14.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 int main(void) { 05 FILE *rfp, *wfp; 06 char buf[BUFSIZ]; 07 int n; 08 09 if ((rfp = fopen("unix.txt", "r")) == NULL) { 10 perror("fopen: unix.txt"); 11 exit(1); 12 } 13 14 if ((wfp = fopen("unix.out", "a")) == NULL) { 15 perror("fopen: unix.out"); 16 exit(1); 17 } 18 19 while ((n = fread(buf, sizeof(char)*2, 3, rfp)) > 0) { 20 fwrite(buf, sizeof(char)*2, n, wfp); 21 } 22 23 fclose(rfp); 24 fclose(wfp); 25 26 return 0; 27 } 항목크기가 char크기의 2배, 이것을 3개, 즉 2*3=6바이트씩 읽어서 출력 # ex2_14.out # cat unix.out Unix System Programming
형식 기반 입력 함수: scanf(3), fscanf(3) 형식 기반 입출력 형식 기반 입력 함수: scanf(3), fscanf(3) fscanf도 scanf가 사용하는 형식 지정 방법을 그대로 사용한다. 성공하면 읽어온 항목의 개수를 리턴한다. 형식 기반 출력 함수: printf(3), fprintf(3) fprintf는 지정한 파일로 형식 지정 방법을 사용하여 출력한다. #include <stdio.h> int scanf(const char *restrict format, ...); int fscanf(FILE *restrict stream, const char *restrict format, ..); #include <stdio.h> int printf(const char *restrict format, /* args */ ...); int fprintf(FILE *restrict stream, const char *restrict format, /*args */ ..)/
[예제 2-15] fscanf 함수 사용하기 01 #include <stdlib.h> ex2_15.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 int main(void) { 05 FILE *rfp; 06 int id, s1, s2, s3, s4, n; 07 08 if ((rfp = fopen("unix.dat", "r")) == NULL) { 09 perror("fopen: unix.dat"); 10 exit(1); 11 } 12 13 printf("학번 평균\n"); 14 while ((n=fscanf(rfp, "%d %d %d %d %d", &id,&s1,&s2,&s3,&s4)) != EOF) { 15 printf("%d : %d\n", id, (s1+s2+s3+s4)/4); 16 } 17 18 fclose(rfp); 19 20 return 0; 21 } # cat unix.dat 2009001 80 95 80 95 2009002 85 90 90 80 # ex2_15.out 학번 평균 2009001 : 87 2009002 : 86
[예제 2-16] fprintf 함수 사용하기 ex2_16.c 01 #include <stdlib.h> 02 #include <stdio.h> 03 04 int main(void) { 05 FILE *rfp, *wfp; 06 int id, s1, s2, s3, s4, n; 07 08 if ((rfp = fopen("unix.dat", "r")) == NULL) { 09 perror("fopen: unix.dat"); 10 exit(1); 11 } 12 13 if ((wfp = fopen("unix.scr", "w")) == NULL) { 14 perror("fopen: unix.scr"); 15 exit(1); 16 } 17 18 fprintf(wfp, “ 학번 평균\n"); 19 while ((n=fscanf(rfp, "%d %d %d %d %d", &id,&s1,&s2,&s3,&s4)) != EOF) { 20 fprintf(wfp, "%d : %d\n", id, (s1+s2+s3+s4)/4); 21 } 22 23 fclose(rfp); 24 fclose(wfp); 25 26 return 0; 27 } 입출력에 형식 지정 기호 사용 # ex2_16.out # cat unix.scr 학번 평균 2009001 : 87 2009002 : 86 # cat unix.dat 2009001 80 95 80 95 2009002 85 90 90 80
파일 오프셋 지정[1] 파일 오프셋 이동: fseek(3) 현재 오프셋 구하기: ftell(3) stream이 가리키는 파일에서 offset에 지정한 크기만큼 오프셋을 이동 whence는 lseek와 같은 값을 사용 fseek는 성공하면 0을 실패하면 EOF를 리턴 현재 오프셋 구하기: ftell(3) 현재 오프셋을 리턴. 오프셋은 파일의 시작에서 현재 위치까지의 바이트 수 #include <stdio.h> int fseek(FILE *stream, long offset, int whence); #include <stdio.h> long ftell(FILE *stream);
오프셋의 저장과 이동: fsetpos(3), fgetpos(3) 파일 오프셋 지정[2] 처음 위치로 오프셋 이동: rewind(3) 오프셋을 파일의 시작 위치로 즉시 이동 오프셋의 저장과 이동: fsetpos(3), fgetpos(3) fgetpos : 파일의 현재 오프셋을 pos가 가리키는 영역에 저장 fsetpos : pos가 가리키는 위치로 파일 오프셋을 이동 #include <stdio.h> void rewind(FILE *stream); #include <stdio.h> int fsetpos(FILE *stream, const fpos_t *pos); int fgetpos(FILE *stream, fpos_t *pos);
[예제 2-17] fseek 함수 사용하기 ex2_17.c ... 04 int main(void) { 05 FILE *fp; 06 int n; 07 long cur; 08 char buf[BUFSIZ]; 09 10 if ((fp = fopen("unix.txt", "r")) == NULL) { 11 perror("fopen: unix.txt"); 12 exit(1); 13 } 14 cur = ftell(fp); printf("Offset cur=%d\n", (int)cur); 17 18 n = fread(buf, sizeof(char), 4, fp); 19 buf[n] = '\0'; 20 printf("-- Read Str=%s\n", buf); 21 22 fseek(fp, 1, SEEK_CUR); 23 24 cur = ftell(fp); 25 printf("Offset cur=%d\n", (int)cur); 26 현재 오프셋 읽기 오프셋 이동
[예제 2-17] fseek 함수 사용하기 27 n = fread(buf, sizeof(char), 6, fp); 28 buf[n] = '\0'; 29 printf("-- Read Str=%s\n", buf); 30 31 cur = 12; 32 fsetpos(fp, &cur); 33 34 fgetpos(fp, &cur); 35 printf("Offset cur=%d\n", (int)cur); 36 37 n = fread(buf, sizeof(char), 13, fp); 38 buf[n] = '\0'; 39 printf("-- Read Str=%s\n", buf); 40 41 fclose(fp); 42 43 return 0; 44 } 오프셋 이동 현재 오프셋 읽어서 지정 # ex2_17.out Offset cur=0 -- Read Str=Unix Offset cur=5 -- Read Str=System Offset cur=12 -- Read Str=Programming
실습 test2.c를 동등한 역할의 저수준 파일 입출력 함수로 변환하라 lseek를 이용하여 다음 데이터 파일을 명령어 라인에 주어진 문자씩 읽 고 다음과 같이 출력하는 프로그램을 작성하라. 표준입출력 라이브러리를 이용하여 위의 문제를 작성하라 ./test 2 데이터 파일 내용 : abcdefghijklmnopqrstuvwxyz 현재파일오프셋 : 0 2 4 6 8 10 12 … 출력 파일 내용 : a c e g I k m l
파일 파일은 관련 있는 데이터들의 집합으로 하드디스크 같은 저장장치에 일정한 형태로 저장된다. 유닉스에서 파일은 데이터를 저장하기 위해서 뿐만 아니라 데이터를 전송하거나 장치에 접근하기 위 해서도 사용한다. 저수준 파일 입출력과 고수준 파일 입출력 저수준 파일 입출력 : 유닉스 커널의 시스템 호출을 사용하여 파일 입출력을 실행하며, 특수 파일도 읽 고 쓸 수 있다. 고수준 파일 입출력 : 표준 입출력 라이브러리로 다양한 형태의 파일 입출력 함수를 제공한다.