파일 타입

Download Report

Transcript 파일 타입

11장 파일
창병모
1
11.1 시스템 호출
2
유닉스 커널(kernel)

하드웨어를 운영 관리하여 다음과 같은 서비스를 제공





3
프로세스 관리(Process management)
파일 관리(File management)
메모리 관리(Memory management)
통신 관리(Communication management)
주변장치 관리(Device management)
시스템 호출(system call)
시스템 호출은 유닉스 커널에 서비스를 요청하기 위한 프로그래밍
인터페이스
응용 프로그램은 시스템 호출을 통해서 유닉스 커널에 서비스를
요청한다.


4
11.2 시스템 호출을 이용한 파일 입출력
5
유닉스에서 파일



6
연속된 바이트의 나열
특별한 다른 포맷을 정하지 않음
디스크 파일뿐만 아니라 외부 장치에 대한 인터페이스
언제 시스템 호출 함수를 사용하나?



To have more fine-grained control over unix permission
bits on file creation.
To use the lower-level functions such as
read/write/mmap as opposed to the C buffered stream I/O
functions.
To open any special device (not a regular file) – tty


7
fopen – c 라이브러리 함수
open – 시스템 호출 함수
파일 열기: open()

파일을 사용하기 위해서는 먼저 open() 시스템 호출을 이용
하여 파일을 열어야 한다.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open (const char *path, int oflag, [ mode_t mode ]);
파일 열기에 성공하면 파일 디스크립터를 리턴, 실패하면 -1을 리턴

8
파일 디스크립터는 열린 파일을 나타내는 번호이다.
파일 열기: 예

fd = open("account",O_RDONLY);

fd = open(argv[1], O_RDWR);

fd = open(argv[1], O_RDWR | O_CREAT, 0600);

fd = open("tmpfile", O_WRONLY|O_CREAT|O_TRUNC, 0600);

fd = open("/sys/log", O_WRONLY|O_APPEND|O_CREAT, 0600);

if ((fd = open("tmpfile", O_WRONLY|O_CREAT|O_EXCL, 0666))==-1)
9
fopen.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd;
if ((fd = open(argv[1], O_RDWR)) == -1)
perror(argv[1]);
printf("파일 %s 열기 성공\n", argv[1]);
close(fd);
exit(0);
}
10
파일 생성: creat()

creat() 시스템 호출




path가 나타내는 파일을 생성하고 쓰기 전용으로 연다.
생성된 파일의 사용권한은 mode로 정한다.
기존 파일이 있는 경우에는 그 내용을 삭제하고 연다.
다음 시스템 호출과 동일
open(path, WRONLY | O_CREAT | O_TRUNC, mode);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat (const char *path, mode_t mode );
파일 생성에 성공하면 생성된 파일의 파일 디스크립터, 실패하면 -1을 리턴
11
파일 닫기: close()

close() 시스템 호출은 fd가 나타내는 파일을 닫는다.
#include <unistd.h>
int close( int fd );
fd가 나타내는 파일을 닫는다. 성공하면 0, 실패하면 -1을 리턴한다.
12
데이터 읽기: read()

read() 시스템 호출



fd가 나타내는 파일에서
nbytes 만큼의 데이터를 읽고
읽은 데이터는 buf에 저장한다.
#include <unistd.h>
ssize_t read ( int fd, void *buf, size_t nbytes );
파일 읽기에 성공하면 읽은 바이트 수, 파일 끝을 만나면 0, 실패하면 -1을 리턴
13
fsize.c
/* 파일의 끝에 도달할 때까지 반복
해서 읽으면서 파일 크기 계산 */
#include <stdio.h>
#include <fcntl.h>
while( (nread = read(fd, buffer,
BUFSIZE)) > 0)
#include <unistd.h>
#define BUFSIZE 512
total += nread;
/* 파일 크기를 계산 한다 */
close(fd);
int main(int argc, char *argv[])
printf ("%s 파일 크기 : %ld 바이트
\n", argv[1], total);
{
char buffer[BUFSIZE];
int fd;
ssize_t nread;
long total = 0;
if ((fd = open(argv[1], O_RDONLY))
== -1)
perror(argv[1]);
14
exit(0);
}
데이터 쓰기: write()

write() 시스템 호출

buf에 있는 nbytes 만큼의 데이터를 fd가 나타내는 파일에 쓴다
#include <unistd.h>
ssize_t write (int fd, void *buf, size_t nbytes);
파일에 쓰기를 성공하면 실제 쓰여진 데이터의 바이트 수를 리턴하고, 실패
하면 -1을 리턴
15
copy.c
if ((fd1 = open(argv[1], O_RDONLY)) ==
-1) {
#include <stdio.h>
#include <fcntl.h>
/* 파일 복사 프로그램 */
perror(argv[1]);
main(int argc, char *argv[])
exit(2);
}
{
if ((fd2 =open(argv[2], O_WRONLY |
int fd1, fd2, n;
char buf[BUFSIZ];
O_CREAT|O_TRUNC 0644)) == -1) {
if (argc != 3) {
perror(argv[2]);
exit(3);
fprintf(stderr,"사용법: %s file1 file2\n",
}
argv[0]);
exit(1);
while ((n = read(fd1, buf, BUFSIZ)) > 0)
}
write(fd2, buf, n); // 읽은 내용을 쓴다.
exit(0);
}
16
11.3 현재 파일 위치
17
파일 위치 포인터(file position pointer)

파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일
위치(current file position)를 가리킨다.
18
파일 위치 포인터 이동: lseek()

lseek() 시스템 호출

임의의 위치로 파일 위치 포인터를 이동시킬 수 있다.
#include <unistd.h>
off_t lseek (int fd, off_t offset, int whence );
이동에 성공하면 현재 위치를 리턴하고 실패하면 -1을 리턴한다.
19
파일 위치 포인터이동: 예

파일 위치 이동




파일 시작으로 이동(rewind)
파일 시작에서 100바이트 위치로
파일 끝으로 이동(append)
레코드 단위로 이동




lseek(fd, 0L, SEEK_SET);
lseek(fd, 100L, SEEK_SET);
lseek(fd, 0L, SEEK_END);
lseek(fd, n * sizeof(record), SEEK_SET); n+1번째 레코드 시작위치로
lseek(fd, sizeof(record), SEEK_CUR);
다음 레코드 시작위치로
lseek(fd, -sizeof(record), SEEK_CUR); 전 레코드 시작위치로 .
파일끝 이후로 이동

20
lseek(fd, sizeof(record), SEEK_END);
파일끝에서 한 레코드
다음 위치로
레코드 저장 예




write(fp,
write(fp,
lseek(fd,
write(fp,
&record1, sizeof(record));
&record2, sizeof(record));
sizeof(record), SEEK_END);
&record3, sizeof(record));
레코드 #1 레코드 #2
21
레코드 #3
dbcreate.c
#include <stdio.h>
#include <fcntl.h>
#include "student.h"
#define START_ID 1201001
/* 학생 정보를 입력받아 데이터베이스 파일에 저장한다. */
int main(int argc, char *argv[])
{
int fd;
struct student record;
if (argc < 2) {
fprintf(stderr, "사용법 : %s file\n", argv[0]);
exit(1);
}
22
dbcreate.c
if ((fd = open(argv[1], O_WRONLY|O_CREAT|O_EXCL, 0640)) == -1) {
perror(argv[1]);
exit(2);
}
printf("%7s %6s %4s\n", "학번", "이름", "점수");
while (scanf("%d %s %d", &record.id, record.name, &record.score) == 3) {
lseek(fd, (record.id - START_ID) * sizeof(record), SEEK_SET);
write(fd, (char *) &record, sizeof(record) );
}
close(fd);
exit(0);
}
23
student.h
#define MAX 24
struct student {
char name[MAX];
int id;
int score;
};
24
dbquery.c
#include <stdio.h>
#include <fcntl.h>
#include "student.h"
#define START_ID 1201001
/* 학번을 입력받아 해당 학생의 레코드를 파일에서 읽어 출력한다. */
int main(int argc, char *argv[])
{
int fd, id;
struct student record;
if (argc < 2) {
fprintf(stderr, "사용법 : %s file\n", argv[0]);
exit(1);
}
if ((fd = open(argv[1], O_RDONLY)) == -1) {
perror(argv[1]);
exit(2);
}
25
dbquery.c
do {
printf("\n검색할 학생의 학번 입력:");
if (scanf("%d", &id) == 1) {
lseek(fd, (id-START_ID)*sizeof(record), SEEK_SET);
if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0))
printf("이름:%s\t 학번:%d\t 점수:%d\n", record.name, record.id,
record.score);
else printf("레코드 %d 없음\n", id);
} else printf(“입력 오류”);
printf("계속하겠습니까?(Y/N)");
scanf(" %c", &c);
} while (c=='Y');
close(fd);
exit(0);
}
26
레코드 수정 과정
(1) 파일로부터 해당 레코드를 읽어서
(2) 이 레코드를 수정한 후에
(3) 수정된 레코드를 다시 파일 내의 원래 위치에 써야 한다.
27
레코드 수정
28
dbupdate.c
#include <stdio.h>
#include <fcntl.h>
#include "student.h"
#define START_ID 1201001
/* 학번을 입력받아 해당 학생 레코드를 수정한다. */
int main(int argc, char *argv[])
{
int fd, id;
char c;
struct student record;
if (argc < 2) {
fprintf(stderr, "사용법 : %s file\n", argv[0]);
exit(1);
}
if ((fd = open(argv[1], O_RDWR)) == -1) {
perror(argv[1]);
exit(2);
}
29
dbupdate.c
}
do {
printf("수정할 학생의 학번 입력: ");
if (scanf("%d", &id) == 1) {
lseek(fd, (long) (id-START_ID)*sizeof(record), SEEK_SET);
if ((read(fd, (char *) &record, sizeof(record)) > 0) && (record.id != 0)) {
printf("학번:%8d\t 이름:%4s\t 점수:%4d\n",
record.id, record.name, record.score);
printf("새로운 점수: ");
scanf("%d", &record.score);
lseek(fd, (long) -sizeof(record), SEEK_CUR);
write(fd, (char *) &record, sizeof(record));
} else printf("레코드 %d 없음\n", id);
} else printf("입력오류\n");
printf("계속하겠습니까?(Y/N)");
scanf(" %c",&c);
} while (c == 'Y');
close(fd);
exit(0);
30
11.4 파일 상태 정보
31
파일 상태(file status)

파일 상태



파일에 대한 모든 정보
블록수, 파일 타입, 접근 권한, 링크수, 파일 소유자의 사용자 ID,
그룹 ID, 파일 크기, 최종 수정 시간 등
예
$ ls -l hello.c
2
-rw-r--r-- 1 chang

cs
617
11월 17일 15:53 hello.c
블록수 ^ 사용권한 링크수 사용자ID 그룹ID 파일 크기 최종 수정 시간
|
파일 타입
32
파일이름
상태 정보: stat()


파일 하나당 하나의 i-노드가 있으며
i-노드 내에 파일에 대한 모든 상태 정보가 저장되어 있다.
#include <sys/types.h>
#include <sys/stat.h>
int stat (const char *pathname, struct stat *buf);
int fstat (int fd, struct stat *buf);
int lstat (int fd, struct stat *buf);
파일의 상태 정보를 가져와서 stat 구조체 buf에
저장한다. 성공하면 0, 실패하면 -1을 리턴한다.
33
stat 구조체
struct stat {
mode_t st_mode;
// 파일 타입과 사용권한
ino_t st_ino;
// i-노드 번호
dev_t st_dev;
// 장치 번호
dev_t st_rdev;
// 특수 파일 장치 번호
nlink_t st_nlink;
// 링크 수
uid_t st_uid;
// 소유자의 사용자 ID
gid_t st_gid;
// 소유자의 그룹 ID
off_t st_size;
// 파일 크기
time_t st_atime;
// 최종 접근 시간
time_t st_mtime;
// 최종 수정 시간
time_t st_ctime;
// 최종 상태 변경 시간
long st_blksize;
// 최적 블록 크기
long st_blocks;
// 파일의 블록 수
}; 34
파일 타입
파일 타입
설명
일반 파일
데이터를 갖고 있는 텍스트 파일 또는 이진 화일
디렉터리 파일
파일의 이름들과 파일 정보에 대한 포인터를 포함하는 파일
문자 장치 파일
문자 단위로 데이터를 전송하는 장치를 나타내는 파일
블록 장치 파일
블록 단위로 데이터를 전송하는 장치를 나타내는 파일
FIFO 파일
프로세스 간 통신에 사용되는 파일로 이름 있는 파이프
소켓
네트워크를 통한 프로세스 간 통신에 사용되는 파일
심볼릭 링크
다른 파일을 가리키는 포인터 역할을 하는 파일
35
파일 타입 검사 함수

파일 타입을 검사하기 위한 매크로 함수
파일 타입
36
파일 타입을 검사하기 위한 매크로 함수
일반 파일
S_ISREG()
디렉터리 파일
S_ISDIR()
문자 장치 파일
S_ISCHR()
블록 장치 파일
S_ISBLK()
FIFO 파일
S_ISFIFO()
소켓
S_ISSOCK()
심볼릭 링크
S_ISLNK()
ftype.c
#include <sys/types.h>
#include <sys/stat.h>
/* 파일 타입을 검사한다. */
int main(int argc, char *argv[])
{
int i;
struct stat buf;
for (i = 1; i < argc; i++) {
printf("%s: ", argv[i]);
if (lstat(argv[i], &buf) < 0) {
perror("lstat()");
continue;
}
37
ftype.c
if (S_ISREG(buf.st_mode))
printf("%s \n", "일반 파일");
if (S_ISDIR(buf.st_mode))
printf("%s \n", "디렉터리");
if (S_ISCHR(buf.st_mode))
printf("%s \n", "문자 장치 파일");
if (S_ISBLK(buf.st_mode))
printf("%s \n", "블록 장치 파일");
if (S_ISFIFO(buf.st_mode))
printf("%s \n", "FIFO 파일");
if (S_ISLNK(buf.st_mode))
printf("%s \n", "심볼릭 링크");
if (S_ISSOCK(buf.st_mode))
printf("%s \n", "소켓");
}
exit(0);
}
38
파일 상태 정보 변경

chmod() 시스템 호출

파일의 상태 정보를 변경
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
path가 나타내는 파일의 사용권한을 mode로 변경한다.
39
fchmod.c
#include <stdio.h>
/* 파일 사용권한을 변경한다. */
main(int argc, char *argv[])
{
long strtol( );
int newmode;
newmode = (int) strtol(argv[1],(char **) NULL, 8);
if (chmod(argv[2], newmode) == -1) {
perror(argv[2]);
exit(1);
}
exit(0);
}
40
11.5 디렉터리
41
디렉터리 구현


디렉터리 내에는 무엇이 저장되어 있을까?
디렉터리 엔트리

#include <dirent.h>
struct dirent {
ino_t d_ino; // i-노드 번호
char d_name[NAME_MAX + 1];
// 파일 이름
}
42
디렉터리 리스트

opendir()



디렉터리 열기 함수
DIR 포인터(열린 디렉터리를 가리키는 포인터) 리턴
readdir()

디렉터리 읽기 함수
#include <sys/types.h>
#include <dirent.h>
DIR *opendir (const char *path);
path 디렉터리를 열고 성공하면 DIR 구조체 포인터를, 실패하면 NULL을 리턴한다.
struct dirent *readdir(DIR *dp);
한 번에 디렉터리 엔트리를 하나씩 읽어서 리턴한다.
43
list1.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <dirent.h>
4 #include <stdio.h>
5
6 /* 디렉터리 내의 파일 이름들을 리스트한다. */
7 int main(int argc, char **argv)
8{
9
DIR *dp;
10
char *dir;
11
struct dirent *d;
12
struct stat st;
13
char path[BUFSIZ+1];
14
44
list1.c
15
16
17
if (argc == 1)
dir = "."; // 현재 디렉터리를 대상으로
else dir = argv[1];
18
19
20
if ((dp = opendir(dir)) == NULL) // 디렉터리 열기
perror(dir);
21
22
23
while ((d = readdir(dp)) != NULL) // 각 디렉터리 엔트리에 대해
printf("%s \n", d->d_name); // 파일 이름 프린트
24
25
closedir(dp);
26
exit(0);
27 }
45
파일 이름/크기 프린트

디렉터리 내에 있는 파일 이름과 그 파일의 크기(블록의 수)
를 프린트하도록 확장
while ((d = readdir(dp)) != NULL) {
sprintf(path, "%s/%s", dir, d->d_name);
if (lstat(path, &st) < 0)
perror(path);
printf("%5d %s", st.st_blocks, d->d_name);
putchar('\n');
}
46
//디렉터리 내의 각 파일
// 파일경로명 만들기
// 파일 상태 정보 가져오기
// 블록 수, 파일 이름 출력
디렉터리 리스트: 예

list2.c


ls –l 명령어처럼 파일의 모든 상태 정보를 프린트
프로그램 구성




47
main()
printStat()
type()
perm()
메인
파일
파일
파일
프로그램
상태 정보 프린트
타입 리턴
접근권한 리턴
list2.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <dirent.h>
4 #include <pwd.h>
5 #include <grp.h>
6 #include <stdio.h>
7
8 char type(mode_t);
9 char *perm(mode_t);
10 void printStat(char*, char*, struct stat*);
11
12 /* 디렉터리 내용을 자세히 리스트한다. */
13 int main(int argc, char **argv)
14 {
15 DIR *dp;
16 char *dir;
17 struct stat st;
18 struct dirent *d;
19 char path[BUFSIZ+1];
48
list2.c
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 }
49
if (argc == 1)
dir = ".";
else dir = argv[1];
if ((dp = opendir(dir)) == NULL) // 디렉터리 열기
perror(dir);
while ((d = readdir(dp)) != NULL) { // 디렉터리의 각 파일에 대해
sprintf(path, "%s/%s", dir, d->d_name); // 파일경로명 만들기
if (lstat(path, &st) < 0) // 파일 상태 정보 가져오기
perror(path);
printStat(path, d->d_name, &st); // 상태 정보 출력
putchar('\n');
}
closedir(dp);
exit(0);
list2.c
40 /* 파일 상태 정보를 출력 */
41 void printStat(char *pathname, char *file, struct stat *st) {
42
43
printf("%5d ", st->st_blocks);
44
printf("%c%s ", type(st->st_mode), perm(st->st_mode));
45
printf("%3d ", st->st_nlink);
46
printf("%s %s ", getpwuid(st->st_uid)->pw_name,
getgrgid(st->st_gid)->gr_name);
47
printf("%9d ", st->st_size);
48
printf("%.12s ", ctime(&st->st_mtime)+4);
49
printf("%s", file);
50 }
50
list2.c
52 /* 파일 타입을 리턴 */
53 char type(mode_t mode) {
54
55 if (S_ISREG(mode))
56
return('-');
57 if (S_ISDIR(mode))
58
return('d');
59 if (S_ISCHR(mode))
60
return('c');
61 if (S_ISBLK(mode))
62
return('b');
63 if (S_ISLNK(mode))
64
return('l');
65 if (S_ISFIFO(mode))
66
return('p');
67 if (S_ISSOCK(mode))
68
return('s');
6951}
list2.c
71 /* 파일 사용권한을 리턴 */
72 char* perm(mode_t mode) {
73 int i;
74 static char perms[10];
75
76 strcpy(perms, "---------“);
77 for (i=0; i < 3; i++) {
78
if (mode & (S_IREAD >> i*3))
79
perms[i*3] = 'r';
80
if (mode & (S_IWRITE >> i*3))
81
perms[i*3+1] = 'w';
82
if (mode & (S_IEXEC >> i*3))
83
perms[i*3+2] = 'x';
84 }
85 return(perms);
8652}
디렉터리 만들기

mkdir() 시스템 호출


path가 나타내는 새로운 디렉터리를 만든다.
"." 와 ".." 파일은 자동적으로 만들어진다
#include <sys/types.h>
#include <sys/stat.h>
int mkdir (const char *path, mode_t mode );
새로운 디렉터리 만들기에 성공하면 0, 실패하면 -1을 리턴한다.
53
디렉터리 삭제

rmdir() 시스템 호출

path가 나타내는 디렉터리가 비어 있으면 삭제한다.
#include <unistd.h>
int rmdir (const char *path);
디렉터리가 비어 있으면 삭제한다. 성공하면 0, 실패하면 -1을 리턴
54
링크


링크는 기존 파일에 대한 또 다른 이름으로
하드 링크와 심볼릭(소프트) 링크가 있다.
#include <unistd.h>
int link(char *existing, char *new);
int unlink(char *path);
55
링크의 구현
link() 시스템 호출


56
기존 파일 existing에 대한 새로운 이름 new 즉 링크를 만든다.
link.c
#include <unistd.h>
int main(int argc, char *argv[ ])
{
if (link(argv[1], argv[2]) == -1) {
exit(1);
}
exit(0);
}
57
unlink.c
#include <unistd.h>
main(int argc, char *argv[ ])
{
int unlink( );
if (unlink(argv[1]) == -1 {
perror(argv[1]);
exit(1);
}
exit(0);
}
58
하드 링크 vs 심볼릭 링크

하드 링크(hard link)




지금까지 살펴본 링크
파일 시스템 내의 i-노드를 가리키므로
같은 파일 시스템 내에서만 사용될 수 있다
심볼릭 링크(symbolic link)




59
소프트 링크(soft link)
실제 파일의 경로명을 저장하고 있는 링크
파일에 대한 간접적인 포인터 역할을 한다.
다른 파일 시스템에 있는 파일도 링크할 수 있다.
심볼릭 링크
int symlink (const char *actualpath, const char *sympath );
심볼릭 링크를 만드는데 성공하면 0, 실패하면 -1을 리턴한다.
#include <unistd.h>
int main(int argc, char *argv[ ])
{
if (symlink(argv[1], argv[2]) == -1) {
exit(1);
}
exit(0);
}
60
핵심 개념






시스템 호출은 유닉스 커널에 서비스를 요청하기 위한 프로그래밍
인터페이스로 응용 프로그램은 시스템 호출을 통해서 유닉스 커널
에 서비스를 요청한다.
파일 디스크립터는 열린 파일을 나타낸다.
파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일 위치
를 가리킨다.
파일 하나당 하나의 i-노드가 있으며 i-노드 내에 파일에 대한 모
든 상태 정보가 저장되어 있다.
디렉터리는 일련의 디렉터리 엔트리들을 포함하고 각 디렉터리 엔
트리는 파일 이름과 그 파일의 i-노드 번호로 구성된다.
링크는 기존 파일에 대한 또 다른 이름으로 하드 링크와 심볼릭(
소프트) 링크가 있다.
61