UNIT 09 표준 I/O 라이브러리 광운대학교로봇 SW 교육원 최상훈
시스템호출 vs 표준 I/O 라이브러리함수 2 Application code read write printf scanf Standard I/O Library buffer read, write User System Call System Buffer (buffer cache) Kernel sync Hardware (terminal, file, ) H/W
스트림과 FILE 구조체 3 스트림 (stream) 표준 I/O라이브러리는스트림을사용하여파일입출력을처리함 파일을생성하거나열면파일스트림을얻게됨 이것을 스트림을파일과연관시켰다 라고말함 FILE 구조체 표준 I/O 라이브러리의스트림을표현하는구조체 특정파일과연결 구조체내부에파일디스크립터를포함 모든프로세스는세가지기본표준스트림제공 표준입력, 표준출력, 표준에러에대핚스트림 stdin, stdout, stderr
스트림과 FILE 구조체 4 /usr/include/stdio.h 49 typedef struct _IO_FILE FILE; <libio.h> 에 _IO_FILE 이정의되어있음 /usr/include/stdio.h 164 /* Standard streams. */ 165 extern struct _IO_FILE *stdin; /* Standard input stream. */ 166 extern struct _IO_FILE *stdout; /* Standard output stream. */ 167 extern struct _IO_FILE *stderr; /* Standard error output stream. */ /usr/include/unistd.h 210 /* Standard file descriptors. */ 211 #define STDIN_FILENO 0 /* Standard input. */ 212 #define STDOUT_FILENO 1 /* Standard output. */ 213 #define STDERR_FILENO 2 /* Standard error output. */
실습 1: 스트림 5 stdin, stdoun, stderr 스트림의파일디스크립터확인하기 파일명 : stdstream.c #include<stdio.h> #include<unistd.h> int main(void) { printf("stdin._fileno:%d\n", stdin->_fileno); printf("stdout._fileno:%d\n", stdout->_fileno); printf("stderr._fileno:%d\n", stderr->_fileno); return 0; $./stdstream stdin._fileno:0 stdout._fileno:1 stderr._fileno:2 $
버퍼링 6 프로그래머에게효율적이고편리한프로그밍환경제공 최적의버퍼크기를라이브러리가자동으로할당 read(), write() 를최소화함으로써성능향상 버퍼링방식 전체버퍼링 줄단위버퍼링 버퍼링없음 표준스트림의버퍼링방식 표준오류는항상버퍼링되지않음 표준입력과표준출력은일반적으로터미널장치를가리키는경우에만줄단위버퍼링이적용되고그외에는전체버퍼링됨
실습 2: 버퍼링예제 (1/2) 7 스트림의버퍼링방식확인하기 파일명 : buffering.c #include<stdio.h> #include<stdlib.h> void pr_stdio(const char *, FILE *); int main(void) { FILE *fp; fputs("enter any character\n", stdout); if(getchar() == EOF){ fprintf(stderr, "getchar error=\n"); exit(1); fputs("one line to standard errro\n", stderr); pr_stdio("stdin", stdin); pr_stdio("stdout", stdout); pr_stdio("stderr", stderr); if((fp = fopen("/etc/motd", "r")) == NULL){ fprintf(stderr, "fopen error\n"); exit(1);
실습 2: 버퍼링예제 (2/2) 8 if(getc(fp) == EOF){ fprintf(stderr, "getc error\n"); exit(1); pr_stdio("/etc/motd", fp); exit(0); void pr_stdio(const char *name, FILE *fp) { printf("stream = %s, ", name); if(fp->_io_file_flags & _IO_UNBUFFERED) printf("unbuffered"); else if(fp->_io_file_flags & _IO_LINE_BUF) printf("line buffered"); else printf("fully buffered"); printf(", buffered size = %d\n", fp->_io_buf_end - fp->_io_buf_base); $./buffering enter any character [enter] one line to standard errro stream = stdin, line buffered, buffered size = 1024 stream = stdout, line buffered, buffered size = 1024 stream = stderr, unbuffered, buffered size = 1 stream = /etc/motd, fully buffered, buffered size = 4096 $
setbuf, setvbuf 9 #include <stdio.h> void setbuf (FILE *fp, char *buf ); int setvbuf (FILE *fp, char *buf, int mode, size_t size ); 버퍼의관리기법을변경 스트림에대해다른입출력연산수행되기젂에호출 setbuf ( ) 버퍼사용을켜거나끌수있음 buf 를 NULL로설정하면버퍼를사용하지않겠다는의미 버퍼를사용하기위해서는, BUFSIZ크기의버퍼사용 setvbf(fp, buf, _IOFBF, BUFSIZ) 와동일
실습 3:setbuf 예제 10 줄단위버퍼링 파일명 : setbuf.c #include<stdio.h> #include<unistd.h> int main(void) { char buf[bufsiz]; setbuf(stdout,buf); printf("hello, "); printf("unix!"); printf("\n"); setbuf(stdout,null); sleep(1); printf("how "); printf("are "); printf("you?"); printf("\n"); return 0; $./setbuf Hello, UNIX! How are you? $ sleep(1); sleep(1); sleep(1); sleep(1); sleep(1); sleep(1);
setbuf, setvbuf 11 setvbuf ( ) 버퍼사용방법을변경 mode _IOFBF : 젂체버퍼링 _IOLBF : 라인버퍼링 _IONBF : 버퍼링없음 buf size mode 가 _IONBF이면무시됨 버퍼의주소 NULL이면표준I/O라이브러리가적젃핚크기 (BUFSIZ) 로직접핛당 mode 가 _IONBF이면무시됨 버퍼의크기
실습 4: 버퍼크기 12 BUFSIZ 와 st_blksize 파일명 : bufsiz.c #include<stdio.h> #include<sys/stat.h> int main(void) { struct stat statbuf; printf("bufsiz:%d\n", BUFSIZ); if(stat(".", &statbuf) == -1){ fprintf(stderr, "stat error\n"); return 1; printf("st_blksize:%ld\n", statbuf.st_blksize); return 0; $./bufsiz BUFSIZ:8192 st_blksize:4096 $
fflush( ) 13 #include <stdio.h> int fflush (FILE *fp); 기능 : 명시적으로버퍼방출 리턴값 : 성공하면 0, 실패하면 EOF (-1) fp 에 NULL 을설정하면, 스트림들의출력버퍼가젂부방출됨
fopen 14 #include <stdio.h> FILE *fopen (const char *pathname, const char *type); 기능 : 해당파일의스트림을연다 리턴값 : 성공하면 FILE 포인터, 실패하면 NULL type r, rb : O_RDONLY w, wb : O_WRONLY O_CREAT O_TRUNC a, ab : O_WRONLY O_CREAT O_APPEND r+, r+b, rb+ : O_RDWR w+, w+b, wb+ : O_RDWR O_CREAT O_TRUNC a+, a+b, ab+ : O_RDWR O_CREAT O_APPEND 기본적으로젂체버퍼링방식이적용됨 단, 터미널에대핚스트림일경우줄단위버퍼링적용
fopen 15 제약 r w a r+ w+ a+ 파일이반드시존재해야함파일의이젂내용이폐기됨 스트림을읽을수있음스트림을쓸수있음스트림의끝에서맊쓸수있음
실습 5:fopen 예제 16 "a+" 파일스트림열기 파일명 : fopen.c #include <stdio.h> int main(void) { FILE *fp; if((fp = fopen("./test", "a+")) == NULL){ fprintf(stderr, "Error\n"); return 0; printf("success!\n"); printf("fd:%d\n", fp->_fileno); fclose(fp); return 0; $./fopen Success! fd:3 $
freopen, fdopen 17 #include <stdio.h> FILE *freopen (const char *pathname, const char *type, FILE *fp ); FILE *fdopen (int filedes, const char *type); freopen ( ) 기능 : 지정된파일을지정된스트림으로연다 리턴값 : 성공하면 FILE 포인터, 실패하면 NULL 스트림이이미열려있으면닫고지정된파일로스트림을다시연다 fdopen ( ) 기능 : 이미열려짂파일디스트립터 (filedes) 에대해스트림과연관시킴 리턴값 : 성공하면 FILE 포인터, 실패하면 NULL open, dup, dup2, fcntl 등의함수로얻은파일디스크립터를사용
실습 6:freopen 예제 18 freopen 파일스트림열기 파일명 : freopen.c #include <stdio.h> int main(void) { char *fname = "test"; FILE *fd; printf("first printf is on the screen.\n"); if((fd = freopen(fname, "w", stdout)) == NULL){ fprintf(stderr,"freopen\n"); return 1; printf("second printf is in this file.\n"); return 0; $./freopen First printf is on the screen. $ cat test Second printf is in this file. $
fclose 19 #include <stdio.h> int fclose ( FILE *fp ); 기능 : 스트림을닫음 리턴값 : 성공하면 0, 실패하면 EOF 버퍼에있는출력자료가방출되고버퍼에있는입력자료는폐기됨 버퍼를스스로핛당했었다면버퍼가해제됨 프로세스가정상적으로종료되면모든 I/O 스트림버퍼에있는자료가방출되고스트림들이모두닫힘
입출력함수의종류 20 문자단위 I/O getc, fgetc, getchar, ungetc putc, fputc, puchar 줄단위 I/O gets, fgets puts, fputs 이짂 (binary) I/O fread, fwrite 서식화된 (formatted) I/O scanf, fscanf, sscanf printf, fprintf, sprintf
getc, fgetc, getchar 21 #include <stdio.h> int getc (FILE *fp ); int fgetc (FILE *fp ); int getchar (void ); 기능 : 스트림에서핚문자를읽어오는함수 리턴값 : 성공하면읽은문자, 실패하거나파일의끝이면 EOF getchar 은표준입력 (stdin) 스트림으로부터문자하나입력받음 getc(stdin) 와 getchar() 동일함
ungetc 22 #include <stdio.h> int ungetc (int c, FILE *fp ); 기능 : 읽은문자를다시스트림에게되돌려놓음 리턴값 : 성공하면 c, 실패하면 EOF
실습 7:fgetc, ungetc 예제 23 ungetc 함수사용하기 파일명 : ungetc.c #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp; int c; if((fp = fopen("test", "r")) == NULL) { fprintf(stderr,"fopen error\n"); return 1; c = fgetc(fp); printf("%c", c); c = fgetc(fp); printf("%c", c); c = fgetc(fp); printf("%c", c); ungetc(c, fp); c = fgetc(fp); printf("%c", c); fclose(fp); return 0; $ cat > test abcdefg [Ctrl+d] $./ungetc abcc$
ferror, feof, clearerr 24 #include <stdio.h> int ferror (FILE *fp); int feof (FILE *fp); void clearerr (FILE *fp); ferror 오류가발생했는지확인 feof 파일끝에도달했는지확인 FILE 구조체안의플래그 오류플래그 파일끝플래그 clearerr 는오류플래그와파일끝플래그를모두해제함
실습 8:feof, ferror 예제 25 feof 와 ferror 파일명 : feof.c #include<stdio.h> int main(void) { int c; while((c = getc(stdin))!= EOF) if(putc(c, stdout) == EOF){ printf("output error\n"); return 1; if(ferror(stdin)){ printf("input error\n"); return 1; if(feof(stdin)){ printf("input eof\n"); return 1; return 0; $./feof hello advc hello advc [Ctrl+d]input eof $ cat > file1 hello advc [Ctrl+d] $./ feof < file1 > file2 $ cat file2 hello advc input eof $
putc, fputc, putchar 26 #include <stdio.h> int putc (int c, FILE *fp ); int fputc (int c, FILE *fp ); int putchar (int c ); 기능 : 스트림에핚문자를출력함 리턴값 : 성공하면 c, 실패하면 EOF putchar 은표준출력 (stdout) 으로출력함 putchar(c) 와 fputc(c, stdout) 동일함
fgets, gets 27 #include <stdio.h> char *fgets (char *buf, int n, FILE *fp ); char *gets (char *buf ); fgets 스트림에서 n 맊큼핚줄을읽음 새줄문자까지읽거나, n-1 개읽어 buf 에저장함 buf 널처리됨 gets 표준입렵에서핚줄을읽음
fputs, puts 28 #include <stdio.h> int fputs (const char *str, FILE *fp ); int puts (const char *str); fputs 스트림에 str( 문자열 ) 을출력함 마지막문자가반드시새줄문자아니어도됨 puts 표준출력으로 str( 문자열 ) 을출력함
fread, fwrite 29 #include <stdio.h> size_t fread (void *ptr, size_t size, size_t nobj, FILE *fp ); size_t fwrite (const void *ptr, size_t size, size_t nobj, FILE *fp ); 기능 : 스트림에 ( 서 ) 이짂자료를쓴다 ( 읽는다 ) 리턴값 : 입출력객체의개수 ptr : 이짂자료의주소 size : 원소의크기 nobj : 원소의개수 fread 함수는오류가발생했거나파일끝에도달했다면 nobj 보다작은값을리턴, ferror 또는 feof 로알아내야함
실습 9:fread, fwrite 예제 1 30 fwrite 를이용핚파일쓰기 파일명 : fwrite.c #include<stdio.h> int main(void) { char data[10] = {'a','b','c','d','e','h'; FILE *fp; if((fp = fopen("./test3", "w")) == NULL){ fprintf(stderr, "fopen error\n"); return 1; if(fwrite(data, sizeof(char), 4, fp)!= 4){ fprintf(stderr, "fwrite error\n"); return 1; fclose(fp); return 0; $./fwrite $ cat test3 abcd$
실습 10:fread, fwrite 예제 2 31 구조체정보파일로쓰기 파일명 : fwrite2.c #include<stdio.h> typedef struct { char name[10]; long total; ITEM; int main(void) { ITEM items[2] = {{"shchoi82",20,{"advc",30; ITEM items2[2]; FILE *fp,*fp2; int nread; int i; if((fp = fopen("./test4", "w")) == NULL){ fprintf(stderr, "fopen error\n"); return 1; if(fwrite(items, sizeof(item), 2, fp)!= 2){ fprintf(stderr, "fwrite error\n"); return 1; fclose(fp);
실습 10:fread, fwrite 예제 2 32 if((fp2 = fopen("./test4", "r")) == NULL){ fprintf(stderr, "fopen error\n"); return 1; nread = fread(items2, sizeof(item), 2, fp2); printf("nread:%d\n", nread); for(i = 0 ; i < nread ; i++){ printf("name : %s\n", items2[i].name); printf("total : %ld\n", items2[i].total); fclose(fp2); return 0; $./fwrite2 nread:2 name : shchoi82 total : 20 name : advc total : 30 $
Binary I/O 33 Binary I/O 의문제점 데이터를쓴시스템과읽는시스템이다를경우문제가발생핛수있음 구조체내의각필드의오프셋은컴파일러와시스템홖경에따라다를수있음 동일시스템홖경에서도컴파일옵션에따라서오프셋이다를수있음 데이터형에대해서각바이트의순서가시스템마다다를수있음 Little Endian, Big Endian 해결방법 고수준의프로토콜에의해서데이터의변홖을수행핚다.
ftell, fseek, rewind 34 #include <stdio.h> long ftell (FILE *fp ); int fseek (FILE *fp, long offset, int whence ); void rewind (FILE *fp); ftell( ) 파일의현재오프셋을돌려줌 fseek( ) 기능 : 파일의현재파일오프셋을변경 리턴값 : 성공하면 0, 실패하면 -1 whence : lseek( ) 에서와사용핚상수와같음 rewind( ) SEEK_SET, SEEK_CUR, SEEK_END 현재파일의오프셋을처음으로이동
ftello, fseeko 35 #include <stdio.h> off_t ftello (FILE *fp ); int fseeko (FILE *fp, off_t offset, int whence ); ftello 성공시현재파일위치지시자, 오류시 -1 fseeko 성공시 0, 오류시 0 이아닌값 ftell, fseek 와비슷하고반홖값타입이 off_t (32 비트이상 ) 라는것이다름
fgetpos, fsetpos 36 #include <stdio.h> int fgetpos (FILE *fp, fpos_t *pos ); int fsetpos (FILE *fp, const fpos_t *pos ); fgetpos 현재파일오프셋을조회함 fsetpos 현재파일오프셋을설정함 ISO C 표준이도입함
실습 11:fgetpos, fsetpos 예제 37 fgetpos 와 fsetpos 사용하기 파일명 : fgetpos.c #include<stdio.h> #include<stdlib.h> int main(void) { FILE* fp; fpos_t pos; if((fp = fopen("./data","r")) == NULL){ fprintf(stderr, "fopen error\n"); exit(1); pos. pos = 10; if(fsetpos(fp, &pos)!= 0) fprintf(stderr, "fsetpos\n"); if(fgetpos(fp, &pos)!= 0) fprintf(stderr, "fgetpos\n"); printf("pos:%ld\n", pos. pos); printf("sizeof:%ld\n", sizeof(pos. pos)); fclose(fp); return 0; $ touch data $./fgetpos pos:10 sizeof:8 $
printf, fprintf, sprintf 38 #include <stdio.h> int printf (const char *format, ); int fprintf (FILE *fp, const char *format, ); int sprintf (char *buf,const char *format, ); int snprintf (char *buf, size_t n, const char *format, ); printf 표준출력에서식화된문자들을출력 fprintf 스트림에서식화된문자들을출력 sprintf 메모리공갂에서식화된문자들을출력 snprintf sprintf 와동일핚기능을하고버퍼의크기를명시적으로지정가능
실습 12:fprintf, snprintf 예제 39 formatted 입출력 파일명 : fprintf.c #include<stdio.h> int main(void) { char sztest[1024] = {0; fprintf(stdout,"%s : %d\n", "stdout", 777); fprintf(stderr,"%s : %d\n", "stderr", 777); snprintf(sztest, sizeof(sztest), "I love %s.\n", "you"); printf("%s", sztest); snprintf(sztest, sizeof(sztest), "%s:%d\n", FILE, LINE ); printf("%s", sztest); return 0; $./fprintf > stdoutfile 2> stderrfile $ cat stdoutfile stdout : 777 I love you. fprintf.c:10 $ cat stderrfile stderr : 777 $
실습 13:printf 예제 40 printf 의출력예 파일명 : printf.c #include<stdio.h> int main() { int x=10; int r; int max; char *string="hello, world"; r=printf("x = %d\n",x); printf("r returned by printf() = %d\n\n",r); printf(":%%s: :%s:\n",string); printf(":%%10s: :%10s:\n",string); printf(":%%15s: :%15s:\n",string); printf(":%%.10s: :%.10s:\n",string); printf(":%%-10s: :%-10s:\n",string); printf(":%%.15s: :%.15s:\n",string); printf(":%%15.10s: :%15.10s:\n",string); printf(":%%-15.10s: :%-15.10s:\n\n",string); printf(":%%.5d: :%.5d:\n",123456789); printf(":%%.5d: :%.5d:\n",123); printf(":%%.10d: :%.10d:\n",123); printf(":%%.5f: :%.5f:\n\n",(double)123);
실습 13:printf 예제 41 printf(" 주소표현 \n"); printf("%%#.8x %#.8x\n",(unsigned)123); printf("0x%%08x 0x%08x\n",(unsigned)123); printf("%%#10x %#010x\n\n",(unsigned)123); printf(" 시간표현 \n"); printf("%%.2d:%%.2d:%%.2d %.2d:%.2d:%.2d\n",1,59,59); printf("%%.2d:%%.2d:%%.2d %.2d:%.2d:%.2d\n",1,1,1); printf("%%.2d:%%.2d:%%.2d %.2d:%.2d:%.2d\n",1,10,100); printf("%%02d:%%02d:%%02d %02d:%02d:%02d\n",1,59,59); printf("%%02d:%%02d:%%02d %02d:%02d:%02d\n",1,1,1); printf("%%02d:%%02d:%%02d %02d:%02d:%02d\n",1,10,100); printf("\n"); printf(":%%-d: :%-d:\n", x); printf(":%%+d: :%+d:\n", x); printf(":%% d: :% d:\n", x); printf(":%%#x: :%#x:\n", x); printf(":%%#o: :%#o:\n", x); printf(":%%010d: :%010d:\n", x); printf("\n"); max=10; printf("%%*.*s :%*.*s:\n",15,max,string); return 0;
실습 13:printf 예제 42 $./printf x = 10 r returned by printf() = 7 :%s: :hello, world: :%10s: :hello, world: :%15s: : hello, world: :%.10s: :hello, wor: :%-10s: :hello, world: :%.15s: :hello, world: :%15.10s: : hello, wor: :%-15.10s: :hello, wor : :%.5d: :123456789: :%.5d: :00123: :%.10d: :0000000123: :%.5f: :123.00000: 주소표현 %#.8x 0x%08x %#10x 0x0000007b 0x0000007b 0x0000007b 시간표현 %.2d:%.2d:%.2d 01:59:59 %.2d:%.2d:%.2d 01:01:01 %.2d:%.2d:%.2d 01:10:100 %02d:%02d:%02d 01:59:59 %02d:%02d:%02d 01:01:01 %02d:%02d:%02d 01:10:100 :%-d: :10: :%+d: :+10: :% d: : 10: :%#x: :0xa: :%#o: :012: :%010d: :0000000010: %*.*s : hello, wor: $
scanf, fscanf, sscanf 43 #include <stdio.h> int scanf (const char *format, ); int fscanf (FILE *fp, const char *format, ); int sscanf (const char *buf,const char *format, ); 리턴값 : 성공하면읽은문자수, 실패하면 EOF scanf( ) 표준입력에서서식화된문자들을입력 fscanf( ) 스트림에서서식화된문자들을입력 sscanf( ) 메모리버퍼에서서식화된문자들을입력
실습 14:scanf, fscanf, sscanf 예제 44 scanf 파일명 : scanf.c #include<stdio.h> int main(void) { FILE *fp; char szname[] = "advc"; char szname2[1024]; char szbuf[1024]; int no = 10, no2; $./scanf name:advc no:10 name:sanghun no:1101144127 $ cat./test name:advc no:10 $ if((fp = fopen("./test", "w+")) == NULL){ fprintf(stderr, "fopen error\n"); return 1; fprintf(fp, "name:%s no:%d\n", szname, no); rewind(fp); fscanf(fp, "name:%s no:%d\n", szname2, &no2); fclose(fp); fprintf(stdout, "name:%s no:%d\n", szname2, no2); strcpy(szbuf, "name:sanghun no:1101144127"); sscanf(szbuf, "name:%s no:%d", szname2, &no2); fprintf(stdout, "name:%s no:%d\n", szname2, no2); return 0;
tmpnam, tmpfile, tempnam 45 #include <stdio.h> char *tmpnam (char *ptr); FILE *tmpfile (void ); char *tempnam (const char *directory,const char *prefix ); 기능 : 프로그램이수행되는동안맊존재하는임시파일을맊들거나, 임시파일이름을맊들때 tmpnam( ) 시스템에서유일핚파일이름을생성, 최대 TMP_MAX 번호출가능 ptr NULL 이아니면 L_tmpnam 맊큼의공갂으로파일이름을저장 NULL 로지정되면정적영역에저장됨 tmpfile( ) wb+ 모드로파일을생성하고, 스트림에대핚포인터를돌려줌 tempnam( ) 생성하고자하는파일의경로와접두어 (5 자이하 ) 를지정함
실습 15:tmpnam 46 임시파일사용하기 파일명 : tmpnam.c #include<stdio.h> int main(void){ char name[l_tmpnam], line[1024]; FILE *fp; printf("%s\n", tmpnam(null)); tmpnam(name); printf("%s\n", name); if ((fp = tmpfile()) == NULL){ fprintf(stderr, "tmpfile error"); return 1; fputs("one line of output\n", fp); rewind(fp); if (fgets(line, sizeof(line), fp) == NULL){ fprintf(stderr, "fgets error"); fputs(line, stdout); return 0; $./tmpnam /tmp/fileaufktu /tmp/fileuevnzq one line of output $
실습 16:tempnam 예제 47 "a+" 파일스트림열기 파일명 : tempnam.c #include<stdio.h> int main(int argc, char *argv[]) { if(argc!= 3){ fprintf(stderr, "usage: a.out <directory> <prefix>\n"); return 1; printf("%s\n", tempnam(argv[1][0]!= ' '? argv[1] : NULL, argv[2][0]!= ' '? argv[2] : NULL)); return 0; $./tempnam /home temp /home/tempvcz4tw $