tonykang22 / study

0 stars 0 forks source link

[리눅스 개발환경] 07. 파일 I/O #77

Open tonykang22 opened 2 years ago

tonykang22 commented 2 years ago

07. 파일 I/O

파일 I/O 개요


파일 디스크립터 (File Descriptor)


파일 디스크립터 테이블 (File Descriptor Table)


파일 테이블 엔트리 (File Table Entry)


표준 파일 디스크립터 (Standard File Descriptor)


파일 생성 및 관리 (creat)

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h>

int creat(const char *pathname, mode_t mode);


File mode bits


파일 생성 실습

int main() {

int fd;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 
char *filename = "/tmp/file";

fd = creat(filename, mode); 
if (fd < 0) {
    printf("creat error: %s\n", strerror(errno));
    return -1; 
    }

return 0; 

}


- 실행 결과

<img width="402" alt="image" src="https://user-images.githubusercontent.com/86760744/179477027-91e662de-e210-42ba-ad09-839e37d3e0ed.png">

<br><br>

## 파일 생성 및 관리 (stat)
``` c
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h>

int stat(const char *path, struct stat *buf);


struct stat {
        dev_t st_dev;                /* 파일을 포함하고 있는 장치 ID */ 
        ino_t st_ino;                  /* inode 번호 */
        mode_t st_mode;         /* 권한 (permissions) */
        nlink_t st_nlink;            /* 하드 링크 수 */
        uid_t st_uid;                  /* user ID */
        gid_t st_gid;                  /* group ID */
        dev_t st_rdev;               /* device ID (특수 파일일 경우) */ 
        off_t st_size;                 /* 바이트 단위의 전체 사이즈 */
        blksize_t st_blksize;     /* filesystem I/O 를 위한 블록 사이즈 */            
        blkcnt_t st_blocks;       /* 할당된 블록의 개수 */         
        time_t st_atime;            /* 마지막 접근 시간 */
        time_t st_mtime;           /* 마지막 편집 시간 */
        time_t st_ctime;            /* 마지막 상태 변경 시간 */
};


stat 예시

int main(int argc, char *argv[]) { struct stat sb; int ret;

if (argc < 2) {
    printf("Usage: %s <file>\n", argv[0]);
    return -1; 
    }

ret = stat(argv[1], &sb); 
if (ret) {
    perror("stat error: ");
    return -1; 
    }

printf("file(%s) is %ld bytes\n", argv[1], sb.st_size);

return 0; 

}


- 예시에서는 sb.st_size 를 가져왔으나, userId, groupId 등 다양한 정보를 가져올 수 있다.
<img width="486" alt="image" src="https://user-images.githubusercontent.com/86760744/179478815-61134138-b1b6-4a1c-be5a-06c5251b8d26.png">

<br><br>

## 권한(Permission) (chmod)
``` c
#include <sys/stat.h>

int chmod(const char *pathname, mode_t mode);


권한(Permission) (chmod) 예시

int chmod(const char *pathname, mode_t mode);

int main() { char *filename = "./creat_example"; int mode = F_OK;

if (access(filename, mode) == 0) {
    if (chmod(filename, S_IRWXU|S_IRWXG) != 0) {
        printf("chmod() error\n");
        return -1;     
        }
    } else {
        printf("file(%s) access error\n", filename);
        return -1; 
    }

return 0; 

}


<br>

- 위의 `creat_example` 파일의 권한이 변경된 것을 확인할 수 있다.

![image](https://user-images.githubusercontent.com/86760744/179722528-9cd89985-48a5-4c6a-a707-0e1d6053fd2d.png)

<br><br>

## 소유권(Ownership) (chown)
``` c
#include <unistd.h>

int chown(const char *pathname, uid_t owner, gid_t group);


소유권(Ownership) (chown) 의 예시

int main() { char *filename = "./creat_example"; int mode = F_OK;

if (access(filename, mode) == 0) {
    if (chown(filename, 1, 2) != 0) {
        printf("chown() error\n");
        return -1; 
        }
    } else {
        printf("file(%s) access error\n", filename);
        return -1; 
    }
return 0; 

}


- 실행 결과
![image](https://user-images.githubusercontent.com/86760744/182078157-1c4cf809-e85e-4c39-86dc-ca1a880b7132.png)

<br><br>

## 파일 열고 닫기 (open)
``` c
#include <sys/types.h>

#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);






파일 열고 닫기 (close)

#include <unistd.h>

int close(int fd);




파일 열고 닫기 (fcntl)

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */);


CMD



struct flock {
    short int l_type        /* 잠김 타입: F_RDLCK, F_WRLCK, or F_UNLCK. */
    short int l_whence; /* 파일의 절대적 위치 */
    __off_t l_start;        /* 파일의 offset */
    __off_t l_len;           /* 잠그고자 하는 파일의 길이 */
    __pid_t l_pid;          /* 잠금을 얻은 프로세스의 pid */



파일 읽고 쓰기 (read)

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);



파일 읽고 쓰기 (write)

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);



파일 읽고 쓰기 (lseek)

#include <sys/types.h>
#include <unistd.h>

off_t leak(int fd, off_t offset, int whence);



실습 프로그램


define LOCK_T 0

define UNLOCK_T 1

define BUFSIZE 1024

int record_lock(int type, int fd, int start, int len);

int main(int argc, char **argv) { int fd; int record_start, record_len; char buf[BUFSIZE] = {0}; int i;

if (argc < 4) {
    printf("Usage: %s [record file] [record start] [record length]\n", argv[0]);
    exit(0); 
}

fd = open(argv[1], O_RDWR); 
if (fd == -1) {
    perror("file open error: ");
    exit(0); 
}

record_start = atoi(argv[2]); 
record_len = atoi(argv[3]); 
if (record_len > BUFSIZE) {
    printf("record_len(%d) cannot over %d\n", record_len, BUFSIZE);
    exit(0); 
}

/* record lock */
if (record_lock(LOCK_T, fd, record_start, record_len) == -1) {
    perror("record lock error: ");
    exit(0); 
}

/* process data */
lseek(fd, record_start, SEEK_SET); 
if (read(fd, buf, record_len) < 0) {
    perror("read error: ");
    exit(0); 
}
printf("record data = %s\n", buf);

/* data modify */
for (i = 0; i < record_len; i++) {
if (buf[i] == '0' || buf[i] == '9') 
    buf[i] = 'x';
}
lseek(fd, record_start, SEEK_SET); 
write(fd, buf, record_len);

/* delay 20 sec */
sleep(20);
printf("record lock process done\n");

/* record unlock */
if (record_lock(UNLOCK_T, fd, record_start, record_len) == -1) {
    perror("record unlock error: ");
    exit(0); 
}

close(fd);

return 0;

}

int record_lock(int type, int fd, int start, int len) { int ret; struct flock lock;

    lock.l_type = (type == LOCK_T) ? F_WRLCK : F_UNLCK;
    lock.l_start = start;
    lock.l_whence = SEEK_SET;
    lock.l_len = len;

    ret = fcntl(fd, F_SETLK, &lock);
    return ret;

}


- data_file.txt이다.

0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789


<br>

- 수행 결과
![image](https://user-images.githubusercontent.com/86760744/182085667-18221d8a-7b6c-4688-a4f9-e7e1351bd26b.png)

<br><br>

## 동기화된 I/O (Synchronized I/O)
### I/O 동기화란?
- 기본적으로 리눅스 시스템은 메모리에 보존된 버퍼 캐시로부터 읽고, 쓰기 행위 시 버퍼 캐시로 쓴다.
- 버퍼가 가득 차거나 동기화 기능을 호출해 버퍼 캐시를 플러시 하기 전까지는 데이터를 디스크에 전송하지 않는다. (I/O Buffering)
- 이렇게 하면 필요한 경우 디스크에 기록하는 비교적 느린 기계적 프로세스를 줄임으로써 성능이 향상된다.
- 그럼에도 불구하고 응용 프로그램이 데이터가 디스크에 기록되는 시기를 제어하려는 경우가 있다.
- 이러한 용도로 리눅스 커널은 동기화된 작업을 위해 몇 가지 옵션을 제공한다.

<img width="653" alt="image" src="https://user-images.githubusercontent.com/86760744/182092506-4d8265f2-0693-4314-9a4b-60db4de5dadf.png">

<br><br>

## fsync()
``` c
#include <unistd.h>

int fsync (int fd);



fdatasync()

#include <unistd.h>

int fdatasync (int fd);



sync()

#include <unistd.h>

void sync (void);



open() 동기화 플래그 (O_SYNC)

fd = open (file, O_WRONLY | O_SYNC);



디렉토리 열기 (opendir)

#include <sys/types.h>
#include <dirent.h>

DIR * opendir (const char *name);
int dirfd (DIR *dir);



디렉토리 읽기 (readdir)

#include <sys/types.h>
#include <dirent.h>

struct dirent * readdir (DIR *dir);
struct dirent {
    ino_t d_ino;                          /* inode 번호 */
    off_t d_off;                           /* 다음 dirent의 오프셋 */ 
    unsigned short d_reclen;    /* 해당 레코드의 길이 */ 
    unsigned char d_type;        /* 파일 타입 */
    char d_name[256];             /* 파일 이름 */
};



디렉토리 닫기 (closedir)

#include <sys/types.h>
#include <dirent.h>

int closedir (DIR *dir);



디렉토리 실습

int main(int argc, char argv[]) { struct dirent entry; DIR *dir; bool found = false;

if (argc < 3) {
    printf("Usage: %s <dir> <file>\n", argv[0]);
    return -1; 
}

dir = opendir(argv[1]); 
if (dir == NULL) {
    perror("opendir error: ");
    return -1; 
}

errno = 0;
while ((entry = readdir(dir)) != NULL) {
    if (strcmp(entry->d_name, argv[2]) == 0) { 
        printf("found! file(%s) exist\n", argv[2]); 
        found = true;
        break;
    } 
}

if (errno) {
    perror("readdir error: "); 
    closedir(dir);
    return -1;
}

if (!found)
    printf("file(%s) doesn't exist!\n", argv[2]);

closedir(dir);
return 0;     

}



<br>

- 실행 결과
![image](https://user-images.githubusercontent.com/86760744/182096281-ca36995e-1a14-4f22-b201-1f331e45c120.png)