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