2. 파일 입출력

Download Report

Transcript 2. 파일 입출력

파일 입출력
유닉스 시스템 프로그래밍
학습 목표
 유닉스에서 파일 입출력의 특징을 이해한다.
 저수준 파일 입출력 함수를 사용할 수 있다.
 고수준 파일 입출력 함수를 사용할 수 있다.
 임시 파일을 생성해 파일 입출력을 할 수 있다.
2/52
목차
1.
저수준 파일입출력 & 고수준 파일입출력 비교
2.
저수준 파일입출력 프로그래밍
3.
고수준 파일입출력 프로그래밍
4.
저수준 및 고수준 파일입출력 인터페이스 변환
5.
임시 파일 생성
3/52
파일 및 파일 입출력
 파일(File)
 논리적 : 관련있는 데이터의 집합(모음)
=> 응용프로그램에서의 기본적인 입출력 객체
 물리적: 하드디스크와 같은 저장장치에 데이터를 저장하는 단위
 특수 파일
• 데이터 저장 목적이 아닌 특정 객체의 인터페이스 목적으로 생성된 파일
• 예: 장치 파일(Device File)
=> 입출력 장치의 인터페이스를 목적으로 추상화된 파일
 파일 입출력
 파일에 데이터를 쓰거나 읽는 동작
 응용 프로그램은 C 표준 입출력 라이브러리나 OS가 제공하는 입출력 시스템호
출을 이용하여 파일 입출력을 수행할 수 있다
• 고수준(High-level) 파일입출력 인터페이스 : C 표준 입출력 라이브러리 함수
• 저수준(Low-level) 파일입출력 인터페이스 : OS 입출력 시스템호출 함수
4/52
저수준 및 고수준 파일입출력 비교
저수준 파일 입출력
고수준 파일 입출력
파일기술자(File Descriptor)
int fd;
파일포인터(File Pointer)
FILE *fp;
특 징
• 바이트 단위로 입출력
• 빠른 파일접근 지원
• 특수파일 접근 가능
• 추상화된 데이터구조를 지
원하기 위해서는 데이터 변환
이 추가로 요구
• 버퍼 단위로 입출력
• 사용하기 용이
• 데이터 입출력 동기화 용이
• 여러 가지 형식의 입출력 함
수를 지원  활용성 높임
주요 함수
open, close, read, write,
lseek, dup, dup2, fcntl, fsync
등
fopen, fclose, fread, fwrite,
fseek, fputs, fgets, fprintf,
fscnf 등
파일지시자
5/52
저수준 파일입출력 : 파일 기술자
 파일 기술자 (File Descriptor)
 현재 열려있는 파일을 구분하는 정수값
 저수준 파일 입출력에서 열린 파일을 참조하는데 사용
 0번 : 표준 입력, 1번 : 표준 출력, 2번 : 표준 오류
1.
2.
3.
파일 기술자 테이블
(File Descriptor
Table)의 인덱스
프로세스별로 하나
의 파일 기술자 테
이블을 가짐
프로세스 생성 시에
기본적으로 표준입
력, 표준출력, 표준
오류 파일은 미리
생성(열림)
6/52
저수준 파일입출력 : 파일 생성과 열고 닫기 (1)
 파일 열기: open(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag [, mode_t mode]);
 path에 지정한 파일을 oflag에 지정한 플래그 값에 따라 열고 파일기술자를 반
환
 oflag 값 :
종 류
O_RDONLY
O_WRONLY
O_RDWR
기 능
파일을 읽기 전용으로 연다.
파일을 쓰기 전용으로 연다.
파일을 읽기와 쓰기가 가능하게 연다.
O_CREAT
파일이 없으면 파일을 생성한다
O_EXCL
O_CREAT 옵션과 함께 사용할 경우 기존에 없는 파일이면 파일을 생성,
파일이 이미 있으면 파일을 생성하지 않고 오류 메시지를 출력한다.
O_APPEND
파일의 맨 끝에 내용을 추가한다.
O_TRUNC
파일을 생성할 때 이미 있는 파일이고 쓰기 옵션으로 열었으면 내용을
모두 지우고 파일의 길이를 0으로 변경한다.
O_NONBLOCK/O_NDELAY
비블로킹(Non-blocking) 입출력
O_SYNC/O_DSYNC
저장장치에 쓰기가 끝나야 쓰기 동작을 완료
7/52
저수준 파일입출력 : 파일 생성과 열고 닫기 (2)
 파일 열기: open(2)
 mode : 파일 접근권한 지정, 0644같이 숫자나 플래그 값으로 지정 가능
mode=S_IRUSR | S_IWUSR;
8/52
저수준 파일입출력 : 파일 생성과 열고 닫기 (3)
 파일 생성 : creat(2)
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *path, mode_t mode);
 파일 생성 함수, open 함수에 파일 생성 기능이 없던 구버전 유닉스에서 사용
 open 함수와 달리 옵션을 지정하는 부분이 없다.
 creat 함수로 파일을 생성하면 파일 기술자를 반환하므로 별도로 open할 필요
없음
 파일 닫기: close(2)
#include <unistd.h>
int close(int fildes);
 프로세스에서 열 수 있는 파일 개수가 제한되어 있으므로 파일의 사용이 끝나
면 닫아야 한다.
9/52
[예제 2-1] 새 파일 열고 닫기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/stat.h>
<fcntl.h>
<unistd.h>
<stdlib.h>
<stdio.h>
int main(void) {
int fd;
mode_t mode;
ex2_1.c
# ls unix.txt
unix.txt: 해당 파일이나 디렉토리가 없음਺
# gcc -o ex2_1.out ex2_1.c
# ex2_1.out# ls -l unix.txt
-rw-r--r--
1 root
other
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
0
1월 6일 13:10 unix.txt
접근권한:644
fd = open("unix.txt", O_CREAT, mode);
if (fd == -1) {
perror("Creat");
exit(1);
}
close(fd);
return 0;
}
10/52
[예제 2-2] O_EXCL 플래그 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
#include
#include
#include
#include
#include
#include
ex2_2.c
<sys/types.h>
<sys/stat.h>
<fcntl.h>
<unistd.h>
<stdlib.h>
<stdio.h>
int main(void) {
int fd;
}
fd = open("unix.txt", O_CREAT | O_EXCL, 0644);
if (fd == -1) {
perror("Excl");
exit(1);
}
close(fd);
# ls unix.txt
# rm unix.txt
return 0;
unix.txt
# ex2_2.out
# ex2_2.out
# ls unix.txt
Excl: File exists
unix.txt
11/52
[예제 2-3] 파일 기술자 할당
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include
#include
#include
#include
#include
#include
ex2_3.c
<sys/types.h>
<sys/stat.h>
<fcntl.h>
<unistd.h>
<stdlib.h>
<stdio.h>
int main(void) {
int fd;
close(0);
표준입력(fd=0)를 닫음
fd = open("unix.txt", O_RDWR);
if (fd == -1) {
perror("Excl");
exit(1);
}
# ex2_3.out
unix.txt : fd = 0
printf("unix.txt : fd = %d\n", fd);
close(fd);
return 0;
}
11행에서 0번을 닫았으므로
새로 생성한 파일은 가장 작은 번호인 0번이 할당된다.
12/52
저수준 파일입출력 : 파일 읽기와 쓰기
 파일 읽기 : read(2)
#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t nbytes);




파일에서 nbytes로 지정한 크기만큼 바이트를 읽어서 buf에 저장
실제로 읽어온 바이트 개수를 반환
반환값이 0이면 파일의 끝에 도달했음을 의미
파일의 종류에 상관없이 무조건 바이트 단위로 읽어온다.
 파일 쓰기 : write(2)
#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t nbytes);
 buf가 가리키는 메모리에서 nbytes로 지정한 크기만큼 파일에 기록
 실제로 쓰기를 수행한 바이트 수를 반환
13/52
[예제 2-4] 파일 읽기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
#include
#include
#include
#include
ex2_4.c
<fcntl.h>
<unistd.h>
<stdlib.h>
<stdio.h>
int main(void) {
int rfd, wfd, n;
char buf[10];
파일기술자 2개 선언
rfd = open("unix.txt", O_RDONLY);
if(rfd == -1) {
perror("Open unix.txt");
exit(1);
}
wfd = open("unix.bak", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (wfd == -1) {
perror("Open unix.bak");
exit(1);
}
14/52
[예제 2-4] 파일 읽기
22
23
24
25
26
27
28
29
30
31 }
while ((n = read(rfd, buf, 6)) > 0)
6바이트씩 읽어온다
if (write(wfd, buf, n) != n) perror("Write");
if (n == -1) perror("Read");
close(rfd);
close(wfd);
return 0;
# ls unix.bak
unix.bak: 해당 파일이나 디렉토리가 없음
# ex2_5.out
# cat unix.bak
Unix System Programming
15/52
저수준 파일입출력 : 파일 오프셋 지정
 파일 오프셋 위치 지정 : lseek(2)
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fildes, off_t offset, int whence);
 offset으로 지정한 크기만큼 오프셋을 이동시킨다.
 offset의 값은 whence값을 기준으로 해석한다.
파일의 시작에서
5번째 위치로 이동
lseek(fd, 5, SEEK_SET);
lseek(fd, 0, SEEK_END);
파일의 끝에서
0번째, 즉 끝으로 이동
 파일 오프셋의 현재 위치를 알려면?
cur_offset = lseek(fd, 0, SEEK_CUR);
16/52
[예제 2-6] 파일 오프셋 사용하기
ex2_6.c
...
07 int main(void) {
08
int fd, n;
09
off_t start, cur;
10
char buf[256];
11
12
fd = open("unix.txt", O_RDONLY);
13
if (fd == -1) {
14
perror("Open unix.txt");
15
exit(1);
16
}
17
18
start = lseek(fd, 0, SEEK_CUR);
19
n = read(fd, buf, 255);
20
buf[n] = '\0';
21
printf("Offset start=%d, Read Str=%s, n=%d\n", (int)start, buf, n);
22
cur = lseek(fd, 0, SEEK_CUR);
23
printf("Offset cur=%d\n", (int)cur);
24
17/52
[예제 2-6] 파일 오프셋 사용하기
25
26
27
28
29
30
31
32
33
start = lseek(fd, 5, SEEK_SET);
n = read(fd, buf, 255);
buf[n] = '\0';
printf("Offset start=", Read Str=%s", (int)start, buf);
close(fd);
return 0;
}
# ex2_6.out
Offset start=0, Read Str=Unix System Programming, n=24
Offset cur=24
Offset start=5, Read Str=System Programming
18/52
저수준 파일입출력 : 파일 기술자 복사
 파일 기술자 복사 : dup(2)
#include <unistd.h>
int dup(int fildes);
 기존 파일 기술자를 인자로 받아 새로운 파일 기술자를 반환
 새로운 파일 기술자는 현재 할당할 수 있는 파일 기술자 중 가장 작은 값으로
자동 할당
 파일 기술자 복사 : dup2(3)
#include <unistd.h>
int dup2(int fildes, int fildes2);
 새로운 파일 기술자를 지정할 수 있다.
19/52
[예제 2-7] 파일 기술자 복사하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include
#include
#include
#include
ex2_7.c
<fcntl.h>
<unistd.h>
<stdlib.h>
<stdio.h>
int main(void) {
int fd, fd1;
fd = open("tmp.aaa", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("Create tmp.aaa");
exit(1);
}
표준출력(1)을 닫았다
close(1);
fd1 = dup(fd);
}
fd를 복사하면 가장 작
은 값인 1로 복사
표준출력을 출력한 내용이 파일
로 저장
printf("DUP FD=%d\n", fd1);
printf("Standard Output Redirection\n");
close(fd);
# ex2_7.out
return 0;
# cat tmp.aaa
DUP FD=1
Standard Output Redirection
20/52
[예제 2-8] dup2 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
#include
#include
#include
#include
ex2_8.c
<fcntl.h>
<unistd.h>
<stdlib.h>
<stdio.h>
int main(void) {
int fd;
fd = open("tmp.bbb", O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("Create tmp.bbb");
exit(1);
표준출력(1)로
}
표준출력을 출력한
지정하여 복사
내용이 파일로 저장된다.
dup2(fd, 1);
printf("DUP2 : Standard Output Redirection\n");
close(fd);
return 0;
}
# ex2_8.out
# cat tmp.bbb
DUP2 : Standard Output Redirection
21/52
저수준 파일입출력 : 파일 기술자 제어
 파일 기술자 제어 : fcntl(2)
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fildes, int cmd, /* arg */ ...);
 파일 기술자가 가리키는 파일에 “cmd"로 지정한 명령을 수행
 “cmd"의 종류에 따라 인자(arg)를 지정할 수 있음
 자주 사용하는 fcntl 명령
22/52
[예제 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
# cat unix.txt
21
flags |= O_APPEND;
Unix System Programming
22
# ex2_9.out
23
if (fcntl(fd, F_SETFL, flags) == -1) {
# cat unix.txt
24
perror("fcntl");
Unix System Programming
25
exit(1);
Hanbit Media
26
}
27
28
if (write(fd, "Hanbit Media", 12) != 12) perror("write");
29
close(fd);
30
파일에 내용 추가
31
return 0;
32 }
23/52
저수준 파일입출력 : 파일 삭제
 unlink(2)
#include <unistd.h>
int unlink(const char *path);
 path에 지정한 파일의 inode에서 링크 수를 감소시킨다.
 링크 수가 0이 되면 path에 지정한 파일이 삭제된다.
 파일 뿐만 아니라 디렉토리(빈 디렉토리 아니어도 됨)도 삭제된다.
 remove(3)
#include <stdio.h>
int remove(const char *path);
 path에 지정한 파일이나 디렉토리를 삭제한다.
 디렉토리인 경우 빈 디렉토리만 삭제한다.
24/52
[예제 2-10] unlink 함수로 파일 삭제하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
ex2_10.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int cnt;
tmp.aaa 파일 삭제
cnt = unlink("tmp.aaa");
if (cnt == -1) {
perror("Unlink tmp.aaa");
exit(1);
}
printf("Unlink tmp.aaa success!!!\n");
return 0;
}
# ls -l tmp*
-rw-r--r-1
-rw-r--r-1
# ex2_10.out
Unlink tmp.aaa
# ls -l tmp*
-rw-r--r-1
root
root
other
other
37
35
1월 6일 17:50 tmp.aaa
1월 6일 18:06 tmp.bbb
35
1월 6일 18:06 tmp.bbb
success!!!
root
other
25/52
저수준 파일입출력 : 파일과 디스크 동기화
 fsync (3)
#include <unistd.h>
int fsync(int fildes);
 메모리에 위치하고 있는 파일 내용을 디스크로 보내 메모리와 디스크 내용을
동기화
 디스크 입출력 속도를 향상시키기 위해 메모리에 디스크 캐시를 유지하며, 디
스크 캐시의 내용과 디스크의 파일 내용을 동기화시킴
26/52
고수준 파일입출력 : 파일 포인터(File Pointer)
 고수준 파일 입출력 : C 언어 표준 입출력 라이브러리
 파일 포인터
 고수준 파일 입출력에서 열린 파일을 가리키는 포인터
 자료형으로 FILE * 형을 사용 -> 구조체에 대한 포인터
27/52
고수준 파일입출력 : 파일 열기와 닫기 (1)
 파일 열기: fopen(3)
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
 filename으로 지정한 파일을 mode로 지정한 모드에 따라 열고 파일 포인터를
반환
 mode 값
FILE *fp;
fp = fopen("unix.txt", "r");
28/52
고수준 파일입출력 : 파일 열기와 닫기 (2)
 파일 닫기: fclose(3)
#include <stdio.h>
int fclose(FILE *stream);
 fopen으로 오픈한 파일을 닫는다.
:
FILE *fp;
fp = fopen("unix.txt", "r");
:
fclose(fp);
:
29/52
고수준 파일입출력 : 문자 기반 입출력 함수
 문자 기반 입력함수: 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, getchar : 매크로
#define getchar( )
 getw : 워드 단위로 읽어온다.
fgetc(stdin)
 문자 기반 출력함수: 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);
#define putchar(c) fputc(c, stdin)
30/52
[예제 2-11] 문자 기반 입출력 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ex2_11.c
#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);
EOF를 만날 때까지 한 문자씩 읽어서 파일로 출력
}
while ((c = fgetc(rfp)) != EOF) {
fputc(c, wfp);
}
fclose(rfp);
fclose(wfp);
return 0;
# cat unix.txt
Unix System Programming
# ex2_11.out
# cat unix.out
Unix System Programming
}
31/52
고수준 파일입출력 : 문자열 기반 입출력
 문자열 기반 입력 함수: gets(3), fgets(3)
#include <stdio.h>
char *gets(char *s);
char *fgets(char *s, int n, FILE *stream);
 gets : 표준 입력에서 문자열을 읽어들인다.
 fgets : 파일(stream)에서 n보다 하나 적게 문자열을 읽어 s에 저장
 문자열 기반 출력 함수: puts(3), fputs(3)
#include <stdio.h>
char *puts(const char *s);
char *fputs(const char *s, FILE *stream);
32/52
[예제 2-12] 문자열 기반 입출력 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ex2_12.c
#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);
한 행씩 buf로 읽어서 파일로 출력
}
while (fgets(buf, BUFSIZ, rfp) != NULL) {
fputs(buf, wfp);
}
fclose(rfp);
fclose(wfp);
# ex2_12.out
# cat unix.out
Unix System Programming
Unix System Programming
return 0;
}
33/52
고수준 파일입출력 : 버퍼 기반 입출력
 버퍼 기반 입력함수: fread(3)
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
 항목의 크기가 size인 데이터를 nitems에 지정한 개수만큼 읽어 ptr에 저장
 성공하면 읽어온 항목 수를 반환
 읽을 항목이 없으면 0을 반환
 버퍼 기반 출력함수: fwrite(3)
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);
 항목의 크기가 size인 데이터를 nitems에서 지정한 개수만큼 ptr에서 읽어서
stream으로 지정한 파일에 출력
 성공하면 출력한 항목의 수를 반환
 오류가 발생하면 EOF(-1)를 반환
34/52
[예제 2-13] fread 함수로 파일 읽기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
ex2_13.c
#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);
# ex2_13.out
}
fclose(rfp);
return 0;
n=3,
n=3,
n=3,
n=3,
buf=Unix S
buf=ystem
buf=Progra
buf=mming
}
35/52
[예제 2-14] fwrite 함수로 파일 출력하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ex2_14.c
#include <stdlib.h>
#include <stdio.h>
int main(void) {
FILE *rfp, *wfp;
char buf[BUFSIZ];
int n;
if ((rfp = fopen("unix.txt", "r")) == NULL) {
perror("fopen: unix.txt");
exit(1);
}
if ((wfp = fopen("unix.out", "a")) == NULL) {
perror("fopen: unix.out");
항목크기가 char크기의 2배, 이것을 3개,
exit(1);
즉 2*3=6바이트씩 읽어서 출력
}
while ((n = fread(buf, sizeof(char)*2, 3, rfp)) > 0) {
fwrite(buf, sizeof(char)*2, n, wfp);
}
fclose(rfp);
fclose(wfp);
return 0;
}
# ex2_14.out
# cat unix.out
Unix System Programming
Unix System Programming
Unix System Programming
36/52
고수준 파일입출력 : 형식 기반 입출력
 형식 기반 입력 함수: scanf(3), fscanf(3)
#include <stdio.h>
int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict stream, const char *restrict format, ..);
 fscanf도 scanf가 사용하는 형식 지정 방법을 그대로 사용한다.
 성공하면 읽어온 항목의 개수를 반환
 형식 기반 출력 함수: printf(3), fprintf(3)
#include <stdio.h>
int printf(const char *restrict format, /* args */ ...);
int fprintf(FILE *restrict stream, const char *restrict format, /*args */ ..)/
 fprintf는 지정한 파일로 형식 지정 방법을 사용하여 출력한다.
37/52
[예제 2-15] fscanf 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
15
16
17
18
19
20
21
ex2_15.c
#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);
}
# cat unix.dat
fclose(rfp);
return 0;
}
2009001 80 95 80 95
2009002 85 90 90 80
# ex2_15.out
학번 평균
2009001 : 87
2009002 : 86
38/52
[예제 2-16] fprintf 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ex2_16.c
#include <stdlib.h>
#include <stdio.h>
int main(void) {
FILE *rfp, *wfp;
int id, s1, s2, s3, s4, n;
if ((rfp = fopen("unix.dat", "r")) == NULL) {
perror("fopen: unix.dat");
exit(1);
}
if ((wfp = fopen("unix.scr", "w")) == NULL) {
perror("fopen: unix.scr");
exit(1);
}
입출력에 형식 지정 기호 사용
fprintf(wfp, “ 학번
평균\n");
while ((n=fscanf(rfp, "%d %d %d %d %d", &id,&s1,&s2,&s3,&s4)) != EOF) {
fprintf(wfp, "%d : %d\n", id, (s1+s2+s3+s4)/4);
}
fclose(rfp);
fclose(wfp);
return 0;
}
# cat unix.dat
2009001 80 95 80 95
2009002 85 90 90 80
# ex2_16.out
# cat unix.scr
학번
평균
2009001 : 87
2009002 : 86
39/52
고수준 파일입출력 : 파일 오프셋 지정 (1)
 파일 오프셋 이동: fseek(3)
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
 stream이 가리키는 파일에서 offset에 지정한 크기만큼 오프셋을 이동
 whence는 lseek와 같은 값을 사용
 fseek는 성공하면 0을 실패하면 EOF를 반환
 현재 오프셋 구하기: ftell(3)
#include <stdio.h>
long ftell(FILE *stream);
 현재 오프셋을 반환
 오프셋은 파일의 시작에서 현재 위치까지의 바이트 수
40/52
고수준 파일입출력 : 파일 오프셋 지정 (2)
 처음 위치로 오프셋 이동: rewind(3)
#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 : 파일의 현재 오프셋을 pos가 가리키는 영역에 저장
 fsetpos : pos가 가리키는 위치로 파일 오프셋을 이동
41/52
[예제 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
15
cur = ftell(fp);
16
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
42/52
[예제 2-17] fseek 함수 사용하기
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
n = fread(buf, sizeof(char), 6, fp);
buf[n] = '\0';
printf("-- Read Str=%s\n", buf);
cur = 12;
fsetpos(fp, &cur);
오프셋 이동
현재 오프셋 읽어서 지정
fgetpos(fp, &cur);
printf("Offset cur=%d\n", (int)cur);
n = fread(buf, sizeof(char), 13, fp);
buf[n] = '\0';
printf("-- Read Str=%s\n", buf);
fclose(fp);
return 0;
}
# ex2_17.out
Offset cur=0
-- Read Str=Unix
Offset cur=5
-- Read Str=System
Offset cur=12
-- Read Str=Programming
43/52
파일 기술자와 파일 포인터 간의 변환
 저수준 파일 입출력의 파일 기술자와 고수준 파일 입출력의 파일 포인터는 상
호 변환 가능
 파일 포인터 생성: fdopen(3)
#include <stdio.h>
FILE *fdopen(int fildes, const char *mode);
 파일 기술자와 모드값을 받아 파일 포인터를 생성
 파일 기술자 생성: fileno(3)
#include <stdio.h>
int fileno(FILE *stream);
 파일 포인터를 인자로 받아 파일 기술자를 반환
44/52
[예제 2-18] fdopen 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ex2_18.c
#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;
}
# ex2_18.out
Read : Unix System Programming
45/52
[예제 2-19] fileno 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include
#include
#include
#include
ex2_19.c
<unistd.h>
<fcntl.h>
<stdlib.h>
<stdio.h>
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);22
close(fd);
return 0;
}
고수준 파일입출력 함수로 파일 오픈
파일 기술자 리턴
저수준 파일읽기 함수로 읽기
# ex2_19.out
fd : 3
Read : Unix System Programming
46/52
임시 파일 사용 (1)
 파일명이 중복되지 않도록 임시파일명 생성
 임시파일명 생성: tmpnam(3)
#include <stdio.h>
char *tmpnam(char *s);
 임시 파일명을 시스템이 알아서 생성
 접두어 지정: tempnam(3)
#include <stdio.h>
char *tempnam(const char *dir, const char *pfx);
 임시파일명에 사용할 디렉토리와 접두어 지정, 접두어는 5글자까지만 지원
char *fname;
fname = tempnam("/tmp", "hanbit");
47/52
임시 파일 사용 (2)
 템플릿을 지정한 임시 파일명 생성: mktemp(3)
#include <stdlib.h>
char *mktemp(char *template);
 임시파일의 템플릿을 받아 임시 파일명 생성
 템플릿은 대문자 ‘X’6개로 마치도록 해야한다.
/tmp/hanbitXXXXXX
48/52
[예제 2-20] 임시 파일명 만들기
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *fname;
char fntmp[BUFSIZ];
char template[32];
ex2_20.c
# ex2_20.out
1. TMP File Name(tmpnam) : /var/tmp/aaaFUaGOe
2. TMP File Name(tmpnam) : /var/tmp/baaGUaGOe
3. TMP File Name(tempnam) : /tmp/hanbiAAAHUaGOe
4. TMP File Name(mktemp) : /tmp/hanbitIUaGOe
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;
}
49/52
임시 파일의 파일 포인터 생성
 tmpfile(3)
 자동으로 w+ 모드로 열린 파일 포인터를 반환
#include <stdio.h>
FILE *tmpfile();
[예제 2-21] tmpfile 함수 사용하기
01
02
03
04
05
06
07
08
09
10
11
12
13
ex2_21.c
#include <stdio.h>
int main(void) {
FILE *fp;
fp = tmpfile();
fputs("unix system", fp);
임시 파일에 출력
fclose(fp);
return 0;
}
50/52
과제물 #1
 교재, pp.116, 연습문제에서 문항 1, 2, 5에서 제시된 프로그램을 작성하
여 제출하여라.
 제출 시에 각각의 프로그램에 대해 설명을 첨부하여라.
 제출: 2012년 3월 19일(월) 수업시간까지.
51/52
유닉스 시스템 프로그래밍