본문으로 바로가기

파일 입출력 - 읽기/쓰기, File descriptor

category Linux 2021. 9. 14. 02:41

3. 파일 읽기/쓰기


Reading files - read(2)

#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 files - write(2)

#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)을 적용할 위치
  • 파일의 시작점부터 현재 위치까지의 byte 수
  • Read(2) / Write(2) 수행 시, 읽은/기록한 byte 수 만큼 순차적으로 이동

  

File Read & Write

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

int main(void) {
    int rfd, wfd, 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);
    }
    
    while ((n = read(rfd, buf, 6)) > 0)
    	if (write(wfd, buf, n) != n) perror("Write");
        
    if (n == -1) perror("Read");
    
    close(rfd);
    close(wfd);
    
    return 0;
}
$ echo “Hello system programming” > hello.txt

$ cat hello.bak
cat: hello.bak: No such file or directory

$ ./readwrite.out

$ cat hello.bak
Hello system programming!

    

File access methods

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

    

Moving the file offset - lseek(2)

#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  : 에러
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
	int fd, n;
    off_t start, 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;
}
$ echo “Linux System Programming” > linux.txt

$ lseek.out
Offset start=0, Read Str=Linux System Programming, n=25
Offset cur=25
Offset start=6, Read Str=System Programming

  

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)

#include <unistd.h>

int fsync (int fd);
  • Page write-back을 강제로 수행
  • fd(file descriptor): 대상 file descriptor
  • Return - 0 : sucess, -1 : error

  

  

File descriptor 다루기


Duplicating FD – dup(2) / dup2(2)

#include <unistd.h>

int dup (int oldfd);
int dup2 (int oldfd, int newfd);
  • oldfd (old file descriptor): 복사하려는 file descriptor
  • newfd (old file descriptor): 새로운 fd 지정, dup()의 경우 할당 가능한 fd 중 가장 작은 값 할당
  • Return: oldfd를 복사한 새로운 fd - -1 : error
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <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);
    }
    
    close(1); // close stdout
    
    // duplicate fd, fd1 will get 1 => redirect standard output to the file
    fd1 = dup(fd);
    
    printf("DUP FD=%d\n", fd1);
    printf("Standard Output Redirection\n");
    close(fd);
    
    return 0;
}
$ redirect.out

$ cat tmp.aaa
DUP FD=1
Standard Output Redirection

    

Manipulating FD – fcntl(2)

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

int fcntl (int fd, int cmd, /* arg */ ...);
  • fd(file descriptor): 대상 file descriptor
  • cmd(command): 수행할 명령 - F_GETFL(상태 flag 읽기), F_SETFL(상태 flag 설정) 등
  • arg(argument): cmd에 필요한 인자들
  • Return: cmd에 따라 다름
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
    int fd, flags;
    
    fd = open("linux.txt", O_RDWR);
    if (fd == -1) {
        perror("open");
        exit(1);
    }
    
    if ((flags = fcntl(fd, F_GETFL)) == -1) {
        perror("fcntl");
        exit(1);
    }
    
    flags |= O_APPEND; // change to append mode
    
    if (fcntl(fd, F_SETFL, flags) == -1) {
        perror("fcntl");
        exit(1);
    }
    
    if (write(fd, "KOREATECH", 9) != 9) perror("write");
    close(fd);
    
    return 0;
}
$ cat linux.txt
Linux system programming

$ changeFD.out

$ cat linux.txt
Unix system programming
KOREATCH

 

'Linux' 카테고리의 다른 글

파일 입출력 - 개요, 열기/닫기  (0) 2021.09.14