File Read & Write

TAEWOO HA·2023년 5월 2일
0

File

목록 보기
2/3

Reading a file

#include <unistd.h>

ssize_t read (int fd, void *but,size_t count);
  • fd : 파일 디스크립터
  • but : 읽을 내용을 저장할 버퍼의 시작 주소
  • count : 읽을 byte 수
  • return : 실제로 읽은 바이트의 수
    • 0 : 파일의 끝(EOF)에 도달, -1 : 에러

디스크의 카운트 만큼 읽어서 메모리의 버퍼만큼 저장
실제로 몇개를 읽었느냐?

Writing to a file

#include <unistd.h>
ssize_t write (int fd, const void *buf , size_t count);

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]={0};
    
    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 hellow.bak");
    exit(1)
    }

==> hello라는 프로그램을 hello.bak으로 복사

...

	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;
}

read를 보면 리드파일 디스크립터, 버퍼공간(10칸),

파일 안에 있는 6개를 읽어서 버퍼로 가지고옴
이 파일은 hello.txt 파일
오프셋은 0번부터 6번까지
여기서 hello.bak 를 wfd가 가리킴
버퍼에 있는 것을 n개 쓴다. n은 뭐냐?
read가 실제로 읽은 바이트의 수
== read 시스템콜이 읽은 만큼 쓰겠다
파일안에 글자가 몇개 있는지 모른다.
글자의 수를 모르기 때문에 while로 반복한다.

직접 실행해보자.

코드:

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

int main(void){
     int rfd, wfd, n;
     char buf[1024]={0};

     rfd = open("a.txt", O_RDONLY);
     if(rfd == -1){
         perror("Open a.txt");
         exit(1);
     }

     wfd = open("result.txt", O_CREAT|O_WRONLY|O_TRUNC, 0666);


     if(wfd == -1){
     perror("Open result.txt");
     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;
 }

권한을 0644로 하면 Permission Denied가 발생한다.

다른 코드:

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

#define BUFFER_SIZE 1024

int main(int argc, char *argv[]) {
    int fd1, fd2, n;
    char buf[BUFFER_SIZE];

    // 명령행 인자 개수 확인
    if(argc != 3) {
        printf("Usage: %s <source> <destination>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // 소스 파일 열기
    if((fd1 = open(argv[1], O_RDONLY)) == -1) {
        perror(argv[1]);
        exit(EXIT_FAILURE);
    }

    // 대상 파일 열기
    if((fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
        perror(argv[2]);
        exit(EXIT_FAILURE);
    }

    // 소스 파일에서 데이터 읽어들이고 대상 파일에 쓰기
    while((n = read(fd1, buf, BUFFER_SIZE)) > 0) {
        if(write(fd2, buf, n) != n) { // 대상 파일에 쓰기
            perror(argv[2]);
            exit(EXIT_FAILURE);
        }
    }

    // read() 함수에서 오류 발생 시 처리
    if(n == -1) {
        perror(argv[1]);
        exit(EXIT_FAILURE);
    }

    // 파일 닫기
    if(close(fd1) == -1 || close(fd2) == -1) {
        perror("close");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

두 코드의 차이점

실행 파일의 권한은 실행 권한에 대해서만 적용되기 때문에, 두 번째 코드는 실행 파일의 권한이 0666이 아니더라도 권한 거부가 일어나지 않습니다. 즉, 파일의 읽기/쓰기 권한은 실행 파일의 권한과 상관 없이 파일 자체의 권한 설정에 따라 결정됩니다. 첫 번째 코드에서 대상 파일의 권한은 O_CREAT 옵션에 의해 생성되기 때문에, 생성된 파일의 권한은 0644로 설정됩니다.

File access method

  • 순차접근 : file을 record 단위로 순서대로 접근

    • 예시) fgetc()
  • 직접접근 : 원하는 블럭을 직접 접근

    • lseek(), seek()

Moving the file offset - lseek

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

off_t lseek(int fd, off, int whence);
  • offset : 이동시킬 byte 수
  • whence : 기준 위치

어디서부터(whence) 얼마나(offset)

  • whence

    • SEEK_SET : 파일의 시작
    • SEEK_CUR : 현재 위치
    • SEEK_END : 파일의 끝
  • 사용 예

    • lseek(fd,5,SEEK_SET)
      • 파일 시작에서 5번째 바이트로 이동
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>

int main(){
	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] = '\n'; // 문자열의 끝
    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); // 처음부터 6칸
    n= read(fd,buf,255); //기존의 버퍼내용은 씌움
    buf[n] = '\n';
    printf("Offset start=%d, Read Str=%s,(int)start, buf);
    
    close(fd);
    
    return 0;
}

코드 작성해보기

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

#define BUFFER_SIZE 1024

int main(void){
    int rfd, wfd, n;
    char buf[BUFFER_SIZE] = {0};

    rfd = open("test.txt", O_RDONLY);
    if(rfd == -1){
        perror("Open test.txt");
        exit(1);
    }

    wfd = open("result.txt", O_CREAT|O_WRONLY|O_TRUNC, 0666);
    if(wfd == -1){
        perror("Open result.txt");
        exit(1);
    }

    lseek(rfd, 23, SEEK_SET); // 문자열 "It is by standing"까지 이동
    while((n=read(rfd,buf,BUFFER_SIZE))>0){
        if(write(wfd,buf,n)!=n) perror("Write");
    }

    if(n==-1) perror("Read");

    close(rfd);
    close(wfd);

    return 0;
}

실행 결과

페이지 캐시

  • 페이지 캐시

    • 프로그램이 디스크에 쓰거나 읽게 되는데 cost가 오래걸린다. recently accessed
  • 디스크 접근 시간 절약을 위해 커널 내부적 기법

  • page write-back

    • 페이지 캐시에 변경된 내용을 디스크에 반영
    • 반영 시기는 커널이 결정
#include <unistd.h>
int fsync(int fd);
  • page write-back을 강제로 수행

0개의 댓글