[시스템 프로그래밍] 파일 읽기, 쓰기
Tags: systemprogramming
Published: 2022-07-02 14:31:44

### Reading a file -read(2)

```c
#include <unistd.h>

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

- `fd` (file descriptor)
    - 읽으려는 파일의 file descriptor
- `buf` (buffer)
    - 읽은 내용을 저장할 buffer의 시작 주소
- `count`
    - 읽을 byte의 수
- return: 실제로 읽은 byte의 수
    - 0: 파일의 끝(EOF)에 도달
    - -1: 에러



### Writing to a file - write(2)

```c
#include <unistd.h>

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

- `fd` (file descriptor)
    - 기록려는 파일의 file descriptor
- `buf` (buffer)
    - 기록할 내용을 저장된 buffer의 시작 주소
- `count`
    - 기록할 byte의 수
- return: 실제로 기록한 byte의 수
    - -1: 에러



### File offset (File position)

- File operation (e.g., read/write)을 적용할 위치
- 파일의 시작점부터 현재 위치까지의 vyte 수
- Read(2)/Write(2) 수행 시, 읽은/기록한 byte 수 만큼 순차적으로 이동



### 실습

파일 내용 복사

```c
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int	main(void)
{
    int		rfd;
    int		wfd;
    int		n;
    char	buf[10];

    rfd = open("hello.txt", O_RDONLY);
    if (rfd == -1)
    {
        perror("Open hello.txt");
        exit(1);
    }
    wfd = open("hello.bak", O_CREAT | O_WRONLY | O_TRUNC, 0644);
    if (wfd == -1)
    {
        perror("Open hello.bak");
        exit(1);
    }
    n = read(rfd, buf, 6);
    while (n > 0)
    {
        if (write(wfd, buf, n) != n)
            perror("Write");
        n = read(rfd, buf, 6);
    }
    if (n == -1)
        perror("Read");
    closd(rfd);
    closd(wfd);
    return (0);
}
```



### File access methods

- Sequantial access (순차 접근)
    - File을 record(or bytes) 단위로 순서대로 접근
        - e.g., fgetc()
- Directed access (직접 접근)
    - 원하는 Block을 직접 접근
        - e.g., lseek(), seek()
- Indexed access
    - Index를 참조하여, 원하는 block를 찾은 후 데이터에 접근



### Moving the file offset - lseek(2)

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

off_t	lseek(int fd, off_t offset, int whence);
```

- `fd` (file descriptor)
    - 대상 file descriptor
- `offset`
    - 이동시킬 byte 수 (양수 or 음수)
- `whence`
    - 기준 위치
    - SEEK_SET: 파일의 시작
    - SEEK_CUR: 현재 위치
    - SEEK_END: 파일의 끝
    - 사용 예
        - lseek(fd, 5, SEEK_SET)
            - 파일 시작에서 5번째 byte로 이동
        - lseek(fd, 0, SEEK_END);
            - 파일의 끝으로 이동
        - cur_offset = lseek(fd, 0, SEEK_CUR);

- return: 이동 후 file offset
    - -1: 에러



### Moving the file offset

```c
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int	main(void)
{
    int		fd;
    int		n;
    off_t	start;
    off_t	cur;
    char	buf[256];
    
    fd = open("linux.txt", O_RDONLY);
    if (fd == -1)
    {
        perror("Open linux.txt");
        exit(1);
    }
    start = lseek(fd, 0, SEEK_CUR);
    n = read(fd, buf, 255);
    buf[n] = '\0';
    printf("Offset start=%d, Read Str=%s, n=%d\n", (int)start, buf, n);
    cur = lseek(fd, 0, SEEK_CUR);
    printf("Offset cur=%d\n", (int)cur);
    start = lseek(fd, 6, SEEK_SET);
    n = read(fd, buf, 255);
    buf[n] = '\0';
    printf("Offset start=%d, Read Str=%s", (int)start, buf);
    close(fd);
    return (0);
}
```



### Page cache & write-Back

- Page cache
    - In-memory store of recently accessed data from an on-disk filesystem
    - Disk 접근 시간 절약을 위해 kernel 내부적 기법
- Page write-back
    - Page cache에 변경 된 내용을 disk에 반영하는 것
    - 반영 시기는 kernel이 결정



### Synchronizing with disks - fsync(2)

```c
#include <unistd.h>

int	fsync(int fd);
```

- Page write-back을 강제로 수행
- `fd` (file descriptor)
    - 대상 file descriptor
- return
    - 0: success
    - -1: error



### 참고

- https://www.youtube.com/watch?v=agGqfV7jwc0&list=PLBrGAFAIyf5pIIFQv_U1dG36L5rylTvbx&index=11