고수준 파일 입출력은 표준 입출력 라이브러리라고도 하며, C 언어의 표준함수로 제공됩니다. 저수준 파일 입출력은 바이트 단위로만 입출력을 수행하므로, 읽어들인 데이터를 가공하는 추가적인 작업이 필요합니다. 이와달리 고수준 파일 입출력은 문자 단위, 행 단위, 버퍼 단위, 형식 기반 입출력 등 편리한 기능을 제공하므로, 프로그램의 용도에 맞게 적당한 함수를 선택하면 됩니다.
파일 포인터
저수준 파일 입출력에서는 열린 파일을 가리키는 데 파일 기술자를 사용하는 한편, 고수준 파일 입출력에서는 파일 포인터를 사용합니다. 파일 포인터는 디스크에서 메모리로 읽어온 파일의 위치(주소)에 관한 정보를 담고 있는 포인터입니다. 또한 파일 기술자는 정수형이지만, 파일 포인터는 시스템 헤더 파일에 정의되어 있는 FILE * 형입니다.
파일 포인터는 FILE 구조체를 가리키는 주소로, 이 구조체는 위 그림에서도 볼수 있듯이 파일 기술자 항목을 포함합니다. 이 파일 기술자를 이용해 파일 포인터와 파일 기술자 사이에서 변환할 수 있습니다. 파일 포인터는 플랫폼 독립적인 구조이므로, 이를 사용하면 어느 플랫폼에서든 동일한 동작을 수행한다는 장점이 있습니다.
파일 열기와 닫기
파일 열기 : fopen(3)
고수준 파일 입출력에서 파일을 여는 함수는 fopen입니다. fopen 함수는 파일 포인터를 리턴합니다.
#include <stdio.h> FILE *fopen(const char *filename, const char *mode);
fopen 함수는 filename으로 지정한 파일을 mode로 지정한 모드로 열고 파일 포인터를 리턴합니다. 두 번째 인자인 mode에 사용할 수 있는 값은 지정되어 있습니다. fopen 함수는 수행에 성공하면 열린 파일의 주소를 파일 포인터로 리턴하고, 실패하면 0을 리턴합니다. fopen 함수의 사용예는 다음과 같습니다. unix.txt 파일을 읽기 전용으로 열고, 파일 포인터를 FILE * 변수인 fp에 저장합니다.
FILE *fp; fp = fopen("unix.txt", "r");
파일 닫기: fclose(3)
fopen 함수로 연 파일을 사용하고 나면 닫아야 합니다. 열린 파일을 닫는 함수는 fclose입니다.
#include <stdio.h> int fclose(FILE *stream);
fclose 함수는 fopen에서 리턴한 파일 포인터를 인자로 지정한 후 메모리에 있던 파일 내용을 디스크에 저장하고 종료합니다. 파일 닫기를 정상적으로 완료하면 0을, 도중에 오류가 발생하면 EOF(-1)을 리턴합니다 fclose 함수의 사용 예는 다음가 같습니다.
FILE *fp; fp = fopen("unix.txt", "r"); fclose(fp);
문자 기반 입출력
고수준 파일 입출력에서 가장 간단한 방법은 저수준 파일 입출력처럼 바이트 단위로 입출력하는 것입니다. 문자 기반 입출력은 데이터를 바이트 스트림으로 이해하고 한 바이트씩 처리하는 함수를 제공합니다.
문자 기반 입력 함수: fgetc(3), getc(3), getchar(3), getw(3)
파일에서 바이트를 읽어오는 함수와 매크로는 다음과 같습니다.
#include <stdio.h> int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void); int getw(FILE *stream);
fgetc 함수는 파일 포인터가 가리키는 파일로부터 문자 한 개를 unsigned char 형태로 읽어옵니다. getc는 매크로로 구현되어 있다는 점을 제외하면 fgetc 함수와 동일한 기능을 수행합니다. 따라서 getc가 실행 속도는 약간 빠르지만, 실행 코드가 확장되므로 메모리를 조금 더 차지합니다. getchar는 표준 입력에서 문자 한 개를 읽어오는 매크로로 다음과 같이 정의되어 있습니다.
#define getchar() getc(stdin)
getw 함수는 파일에서 워드(word) 단위로 읽어옵니다. 워드의 크기는 int형의 크기로, 시스템에 따라 달라질 수 있습니다. 문자 입출력 함수의 동작에서 오류가 발생하면 EOF(-1)를 리턴합니다. 이들 함수의 리턴형이 char가 아닌 int로 정의된 이유는 char형으로 처리할 경우 값의 범위 제한으로 인해 EOF와 십진수 255를 구별할 수 없기 때문입니다(EOF는 -1로 정의되어 있는 상수로, 이를 2진수로 표현하면 11111111인데, 십진수 255도 char로 이해하면 같은 11111111이 됩니다).
문자 기반 출력 함수: fputc(3), putc(3), putchar(3), putw(3)
문자를 파일에 출력하는 함수와 매크로는 다음과 같습니다.
#include <stdio.h> int fputc(int c, *stream); int putc(int c, *stream); int putchar(int c); int putw(int w, FILE *stream);
fputc 함수는 인자로 받은 int 데이터 c를 unsigned char로 변환해 파일에 씁니다. putc는 fputc와 같은 동작을 수행합니다. putc는 getc와 마찬가지로 매크로로 구현되어 있습니다. putchar는 표준 출력으로 한 문자를 출력하는 매크로로, getchar처럼 다음과 같이 정의 되어 있습니다.
#define putchar(c) putc(c, stdout)
putw 함수는 워드 단위로 파일에 출력합니다. 워드의 크기는 getw와 마찬가지로 int형의 크기입니다. 문자를 성공적으로 출력하면 해당 문자값을, 오류가 발생하면 EOF를 리턴합니다. 문자 기반 입출력 함수를 사용해 한 파일의 내용을 다른 파일로 복사해보겠습니다.
#include <stdlib.h> #include <stdio.h> int main(void) { FILE *rfp, *wfp; int c; if((rfp = fopen("unix.txt", "r")) == NULL) { perror("fopen: unix.txt"); exit(1); } if((wfp = fopen("unix.out", "w")) == NULL) { perror("fopen: unix.out"); exit(1); } while((c = fgetc(rfp)) != EOF) { fputc(c, wfp); } fclose(rfp); fclose(wfp); return 0; }
문자열 기반 입출력
고수준 파일 입출력에서는 한 번에 여러 문자, 즉 문자열을 입출력하는 방법을 제공합니다.
문자열 기반 입력 함수: gets(3), fgets(3)
#include <stdio.h> char *gets(char *s); char *fgets(char *s, int n, FILE *stream);
gets 함수는 표준 입력에서 문자열을 읽어들입니다. 문자열은 엔터키를 입력하거나, 파일의 끝을 만날 때까지 읽습니다. gets는 읽어들인 문자열의 끝에서 개행 문자(엔터키 값)를 제외하고 널 문자를 채워 인자 s가 가리키는 영역에 저장하고 리턴합니다. gets는 인자 s가 확보하고 있기 메모리의 크기를 알 수 없기 때문에 s가 가득 찬 후에도 계속 읽어들일 수 있습니다. 이 때문에 보안 침해 문제가 발생할 수 있으므로 가능하면 gets는 사용하지 않는 것이 좋습니다.
fgets 함수는 파일 포인터가 가리키는 파일에서 정수 n으로 지정한 길이보다 하나 적게 문자열을 읽어 s에 저장합니다. n의 길이만큼 읽는 도중에 개행 문자를 만나거나, 파일의 끝을 만나면 해당 지점까지만 읽어옵니다. fgets는 gets와 달리 개행 문자도 s에 저장하고, 널 문자로 마칩니다. 두 함수 모두 오류인 경우와 파일의 끝에 도달한 경우 읽어올 수 없으므로 NULL을 반환합니다. 정상적으로 입력을 수행하면 s의 시작 주소를 리턴합니다.
문자열 기반 출력 함수: puts(3), fputs(3)
#include <stdio.h> char *puts(const char *s); char *fputs(const char *s, FILE *stream);
puts 함수는 s가 가리키는 문자열을 표준 출력으로 출력합니다. 이때 개행 문자를 추가해 출력합니다. fputs는 s가 가리키는 문자열을 파일 포인터가 가리키는 파일로 출력합니다. fputs는 출력할 때 개행 문자를 추가하지 않습니다.
#include <stdlib.h> #include <stdio.h> int main(void) { FILE *rfp, *wfp; char buf[BUFSIZ]; if((rfp = fopen("unix.txt", "r")) == NULL) { perror("fopen: unix.txt"); exit(1); } if((wfp = fopen("unix.out", "a")) == NULL) { perror("fopen: unix.out"); exit(1); } while(fgets(buf, BUFSIZ, rfp) != NULL) { fputs(buf, wfp); } fclose(rfp); fclose(wfp); return 0; }
버퍼 기반 입출력
고수준 파일 입출력에서는 한 번에 입출력하는 버퍼의 크기를 지정해 버퍼 단위로 파일 입출력을 수행하는 방법을 제공합니다.
버퍼 기반 입력 함수: fread(3)
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
각각 옵셔에 대한 설명은 ptr: 버퍼 주소, size: 버퍼 크기, nitems: 읽어올 항목 수, stream: 파일 포인터 입니다. fread 함수는 항목의 크기가 size인 데이터를 nitems에서 지정한 개수만큼 읽어서 ptr이 가리키는 버퍼에 저장합니다. 성공적으로 수행하면 읽어온 항목 수를 리턴합니다. 읽을 항목이 없으면 0을, 파일의 끝을 만나면 EOF를 리턴합니다.
fread 함수를 사용해 unix.txt 파일을 읽어 표준 출력으로 출력해보겠습니다.
#include <stdlib.h> #include <stdio.h> int main(void) { FILE *rfp; char buf[BUFSIZ]; int n; if((rfp = fopen("unix.txt", "r")) == NULL) { perror("fopen: unix.txt"); exit(1); } while((n=fread(buf, sizeof(char)*2, 3, rfp)) > 0) { buf[6] = '\0'; printf("n=%d, buf=%s\n", n, buf); } fclose(rfp); return 0; }
# ./ex2_13_exe
n=3, buf=Unix S
n=3, buf=ystem
n=3, buf=Progra
n=3, buf=mming
n=3, buf=Hanbit
n=3, buf= Media
버퍼 기반 출력 함수: fwrite(3)
#include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
fwrite 함수는 항목의 크기가 size인 데이터를 nitems에서 지정한 갯수만큼 ptr에서 읽어 stream으로 지정한 파일에 출력합니다. 성공적으로 수행하면 출력한 항목의 수를, 오류가 발생하면 EOF를 리턴합니다.
형식 기반 입출력
fgets 같은 함수는 문자열의 형식을 고려하지 않고, 한 행씩 읽어옵니다. 예를 들어, 다음과 같은 성적 파일을 한 행씩 읽어온다고 가정하면 과목별 점수를 구분해 떼어내는 번거로운 작업을 해야 합니다. 고수준 파일 입출력은 이와 같이 정해진 형식이 있는 파일을 읽어들일 때 유용하게 사용할 수 있는 형식 기반 입출력 함수를 제공합니다.
형식 기반 입력 함수: scanf(3), fscanf(3)
#include <stdio.h> int scanf(const char *restrict format, ...); int fscanf(FILE *restrict stream, const char *restrict format, ...);
형식 기반 파일 입력은 C 언어에서 다루는 scanf 함수입니다. scanf 함수는 표준 입력에서 입력을 받고, fscanf는 지정한 파일에서 입력을 받습니다. fscanf도 scanf가 사용하는 형식 지정 방법을 그대로 사용하므로 여기서 다시 설명하지 않습니다. 두 함수는 성공적으로 수행하면 읽어온 항목의 개수를 리턴합니다. 입력값이 형식에 맞지 않거나, 너무 빨리 파일의 끝에 도달하면 0을 리턴합니다. 형식에 맞는지 확인하기 전에 파일의 끝을 만나면 EOF를 리턴합니다.
앞에서 예로 든 성적 파일(unix.dat)에서 성적을 읽어 평균을 구해보겠습니다. 아울러 fscanf 함수로 형식 기반 입력 방법을 살펴보겠습니다.
#include <stdlib.h> #include <stdio.h> int main(void) { FILE *rfp; int id, s1, s2, s3, s4, n; if((rfp = fopen("unix.dat", "r")) == NULL) { perror("fopen: unix.dat"); exit(1); } printf("학번 평균\n"); while((n=fscanf(rfp, "%d %d %d %d %d", &id, &s1, &s2, &s3, &s4)) != EOF) { printf("%d : %d\n", id, (s1+s2+s3+s4)/4); } fclose(rfp); return 0; }
# ./ex2_15_exe
학번 평균
2009001 : 87
2009002 : 86
파일의 끝을 만날 때까지 입력 파일의 형식에 따라 학번과 성적을 한 행씩 읽어옵니다. 읽어온 데이터는 이미 분리되어 있으므로 15행과 같이 별도의 작업 없이 바로 계산해 출력할 수 있습니다.
형식 기반 출력 함수: printf(3), fprintf(3)
#include <stdio.h> int printf(const char *restrict format, /* args */ ...); int fprintf(FILE *restrict stream, const char *restrict format, /* args */ ...);
형식 기반 파일 출력도 C 언어에서 다룬 printf 함수를 기반으로 합니다. printf 함수는 표준 출력으로 출력하고, fprintf는 지정한 파일로 출력합니다. 출력 대상이 파일이기 때문에 첫 번째 인자가 파일 포인터가 된다는 점이 다를 뿐입니다. fprintf도 printf가 사용하는 형식 지정 방법을 그대로 사용합니다. 두 함수 모두 성공적으로 수행하면 출력한 문자 수를, 오류가 발생하면 EOF를 리턴합니다.
파일 오프셋 지정
앞서 저수준 파일 입출력에서 lseek 함수는 파일의 내용을 읽거나 쓰면 현재 읽을 위치나 쓸 위치를 알려주는 오프셋을 지정하는 기능을 제공함을 배웠습니다. 고수준 파일 입출력에서도 이와 같은 기능을 제공합니다. 저수준 파일 입출력의 경우 이 기능을 수행하는 함수가 lseek뿐이지만, 고수준 파일 입출력에서는 다양한 함수를 제공합니다.
파일 오프셋 이동: fseek(3)
#include <stdio.h> int fseek(FILE *stream, long offset, int whence);
fseek 함수는 lseek와 유사학 동작합니다. fseek 함수는 stream이 가리키는 파일에서 offset에 지정한 크기만큼 오프셋을 이동시킵니다. whence 는 offset 값을 해석하는 방법을 결정하는 상수로, lseek에서와 같은 의미를 지닙니다. whence에 사용할 수 있는 값은 다음과 같습니다.
SEEK_SET |
파일의 시작 기준 |
SEEK_CUR |
현재 위치 기준 |
SEEK_END |
파일의 끝 기준 |
lseek 함수는 성공하면 변경된 오프셋을 리턴하지만 fseek 함수는 성공하면 0을, 실패하면 EOF를 리턴합니다. 따라서 현재 오프셋을 구할 때 lseek와 같이 다음처럼 하면 안됩니다.
cur = fseek(fp, 0, SEEK_CUR);
현재 오프셋은 다음에 설명하는 ftell 함수를 사용해 구할 수 있습니다.
현재 오프셋 구하기 : ftell(3)
#include <stdio.h> long ftell(FILE *stream);
ftell 함수는 인자로 지정한 파일의 현재 오프셋을 리턴합니다. ftell이 리턴하는 오프셋은 파일의 시작에서 현재 오프셋 위치까지의 바이트 수입니다. ftell 함수는 수행에 실패하면 EOF를 리턴합니다. 따라서 현재 오프셋 값을 구하려면 다음과 같이 ftell 함수를 사용합니다.
long cur; cur = ftell(fp);
처음 위치로 오프셋 이동: rewind(3)
rewind 함수는 오프셋을 파일의 시작으로 즉시 이동시킵니다.
#include <stdio.h> void rewind(FILE *stream);
오프셋의 저장과 이동: fsetpos(3), fgetpos(3)
#include <stdio.h> int fsetpos(FILE *stream, const fpos_t *pos); int fgetpos(FILE *stream, fpos_t *pos);
fgetpos와 fsetpos는 ANSI C에서 새로 정의한 함수 입니다. fgetpos 함수는 파일의 현재 오프셋을 pos가 가리키는 영역에 저장합니다. fsetpos 함수는 pos가 가리키는 영역의 값으로 파일 오프셋을 변경합니다. 두 함수 모두 성공하면 0을, 실패하면 0이 아닌 값을 리턴합니다.
파일과 디스크 동기화 함수
고수준 파일 입출력 함수는 기본적으로 버퍼의 내용을 디스크로 옮겨 씁니다. 그러나 이를 항상 보장할 수는 없기 때문에 필요에 따라 강제로 수행하도록 해야 합니다. 이를 위해 고수준 파일 입출력에서는 fflush(3) 함수를 제공합니다.
#include <stdio.h> int fflush(FILE *stream);
fflush 함수는 버퍼에 있는 데이터를 파일에 기록합니다. 파일을 읽기 전용으로 연 경우 버퍼에 있는 내용을 모두 비웁니다. 파일 포인터가 NULL이면 쓰기 전용으로 연 모든 파일에 데이터를 씁니다.
파일 기술자와 파일 포인터 간 변환
저수준 파일 입출력에서는 열린 파일을 가리킬 때 파일 기술자를 사용하며, 고수준 파일 입출력에서는 파일 포인터를 사용합니다. 파일 기술자와 파일 포인터를 상호 변환할 수 있습니다. 파일 기술자에서 파일 포인터를 생성하려면 fdopen(3) 함수를 사용하며, 파일 포인터로부터 파일 기술자 정보를 추출하려면 fileno(3) 함수를 사용합니다.
기능 |
함수원형 |
파일 기술자 → 파일 포인터 |
FILE *fdopen(int fildes, const char *mode); |
파일 포인터 → 파일 기술자 |
int fileno(FILE *stream); |
파일 포인터 생성 : fdopen(3)
#include <stdio.h> FILE *fdopen(int fildes, const char *mode);
fdopen 함수는 파일 기술자와 모드(읽기, 쓰기 등)를 인자로 받아 파일 포인터를 생성합니다. 두 번째 인자인 mode에 사용할 수 있는 값은 fopen에서 사용한 값으로 위 표에서 설명했습니다. mode에 값을 지정할 때는 파일 기술자를 열 때와 같은 종류의 값으로 해야합니다. 저수준에서는 읽기 전용(O_RDONLY)으로 열었는데, 고수준으로 변환하면서 쓰기(w)로 하면 정상적으로 동작하지 않습니다. fdopend 함수는 성공하면 파일 포인터를, 실패하면 널 포인터를 리턴합니다.
open 함수로 파일을 열어 리턴받은 파일 기술자로 fdopen 함수에 전달해 파일 포인터를 생성하고, fgets 함수를 사용해 파일을 읽어보겠습니다.
#include <fcntl.h> #include <stdlib.h> #include <stdio.h> int main(void) { FILE *fp; int fd; char str[BUFSIZ]; fd = open("unix.txt", O_RDONLY); if(fd == -1) { perror("open"); exit(1); } fp = fdopen(fd, "r"); fgets(str, BUFSIZ, fp); printf("Read : %s\n", str); fclose(fp); return 0; }
파일 기술자 생성: fileno(3)
fileno 함수는 파일 포인터를 인자로 받아 파일 기술자를 리턴합니다.
#include <stdio.h> int fileno(FILE *stream);
fopen으로 파일을 열고 리턴받은 파일 포인터를 fileno 함수로 전달해 파일 기술자를 추출해보겠습니다.
#include#include #include #include int main(void) { FILE *fp; int fd, n; char str[BUFSIZ]; fp = fopen("unix.txt", "r"); if (fp == NULL) { perror("fopen"); exit(1); } fd = fileno(fp); printf("fd : %d\n", fd); n = read(fd, str, BUFSIZ); str[n] = '\0'; printf("Read : %s\n", str); close(fd); return 0; }
# ./ex2_19_exe
fd : 3
Read : Unix System Programming
Hanbit Media
프로그램을 수행하는 과정에서 데이터를 파일에 임시로 저장해야 할 때가 있습니다. 그런데 같은 프로그램을 여러 사용자가 동시에 사용하는 경우 임시 파일명이 동일하면 문제가 발생할 수 있습니다. 따라서 임시 파일명이 중복되지 않도록 생성하는 방법이 필요합니다.
임시 파일명 생성
기존 파일과 중복되지 않는 임시 파일명을 만들어주는 함수로 tmpnam, tempnam, mktemp가 있습니다. 이들 함수는 파일명만 리턴하므로 저수준이나 고수준 파일 생성 함수로 파일을 생성해 사용해야 합니다.
임시 파일명 생성 : tmpnam(3)
#include <stdio.h> char *tmpnam(char *s);
tmpnam 함수를 사용하면 임시 파일명을 시스템이 알아서 저장합니다. 인자가 있을 경우 해당 인자가 가리키는 곳에 임시 파일명을 저장하고, 인자가 NULL일 경우 임시 파일명을 리턴합니다.
접두어를 지정한 임시 파일명 생성 : tempnam(3)
#include <stdio.h> char *tmpnam(const char *dir, const char *pfx);
tempnam 함수는 임시 파일명에 사용할 디렉토리와 접두어를 지정할 수 있도록 하며 생성된 파일명을 리턴합니다. 예를 들어, /tmp 디렉토리로 지정하고 접두어를 'hanbit'으로 하려면 다음과 같이 하면 됩니다.
#include <stdio.h> char *tmpnam(const char *dir, const char *pfx);
그러나 tempnam 함수는 접두어를 5글자만 허용하므로 실제로는 'hanbi'만 생성될 것입니다.
템플릿을 지정한 임시 파일명 생성 : mktemp(3)
#include <stdio.h> char *mktemp(char *template);
mktemp 함수는 인자로 임시 파일의 템플릿을 받아 이를 임시 파일명으로 변환해 리턴합니다. 인자로 지정하는 템플릿은 대문자 'X' 6개로 마치도록 해야 합니다. 예를 들어보겠습니다.
/tmp/hanbitXXXXXX
mktemp 함수는 대문자 'X' 부분을 다른 문자로 대체해 임시 파일명을 만듭니다. 한 프로세스에서 한 템플릿당 26개의 유일한 임시 파일을 만들 수 있습니다. 임시 파일명 생성에 실패하면 널 문자열을 리턴합니다. 다음은 다양한 방법으로 임시 파일명을 생성하는 예를 보여줍니다.
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char *fname; char fntmp[BUFSIZ]; char template[32]; fname = tmpnam(NULL); printf("1. TMP File Name(tmpnam) : %s\n", fname); tmpnam(fntmp); printf("2. TMP File Name(tmpnam) : %s\n", fntmp); fname = tempnam("/tmp", "hanbit"); printf("3. TMP File Name(tempnam) : %s\n", fname); strcpy(template, "/tmp/hanbitXXXXXX"); fname = mktemp(template); printf("4. TMP File Name(mktemp) : %s\n", fname); return 0; }
# ./ex2_20_exe
1. TMP File Name(tmpnam) : /tmp/file1Tipig
2. TMP File Name(tmpnam) : /tmp/fileXWJOAf
3. TMP File Name(tempnam) : /tmp/hanbiD5reTe
4. TMP File Name(mktemp) : /tmp/hanbitdfmFbe
임시 파일의 파일 포인터 생성
tmpnam, tempnam, mktemp 함수는 임시 파일의 이름만 생성합니다. 따라서 해당 임시 파일을 대상으로 입출력을 수행하려면 파일을 열어야 합니다. 대부분의 경우 프로그램을 수행할 때 임시파일명을 반드시 알아야 하는 것은 아닙니다. 임시 파일명은 알 필요가 없고 단지 임시 파일에 대한 파일 포인터만 필요하면 tmpfile 함수를 사용합니다. tmpfile 함수는 자동으로 w+ 모드로 열린 파일 포인터를 리턴합니다. 이 파일 포인터는 바로 입출력에 사용할 수 있습니다.
#include <stdio.h> FILE *tmpfile();
임시 파일을 생성하고 리턴된 파일 포인터를 사용해 데이터를 출력해보겠습니다.
#include <stdio.h> int main(void) { FILE *fp; fp = tmpfile(); fputs("unix system", fp); fclose(fp); return 0; }
'프로그래밍(TA, AA) > C C++' 카테고리의 다른 글
[시스템프로그래밍] 시스템 정보 (0) | 2017.08.04 |
---|---|
[시스템프로그래밍] Segmentation Fault (0) | 2017.08.03 |
[시스템프로그래밍] 파일과 디렉토리 (0) | 2017.08.03 |
[시스템프로그래밍] 저수준 파일 입출력 (0) | 2017.07.30 |
[시스템프로그래밍] 유닉스 시스템 프로그래밍 개요 (0) | 2017.07.27 |