• 시스템 호출은 커널에 서비스를 요청하기 위한 프로그래밍 인터페이스로 응용 프로그램은 시스템 호출을 통해서 커널에 서비스를 요청할 수 있다.
• 파일 디스크립터는 열린 파일을 나타낸다.
• open() 시스템 호출은 파일을 열고 열린 파일의 파일 디스크립터를 반환한다.
• read() 시스템 호출은 지정된 파일에서 원하는 만큼의 데이터를 읽고 write() 시스템 호출은 지정된 파일에 원하는 만큼의 데이터를 쓴다.
• 파일 위치 포인터는 파일 내에 읽거나 쓸 위치인 현재 파일 위치를 가리킨다.
• lseek() 시스템 호출은 지정된 파일의 현재 파일 위치를 원하는 위치로 이동시킨다.
유닉스에서의 파일이란
int open (const char *path, int oflag, [ mode_t mode ]);
1 2 3
파일 열기에 성공하면 파일 디스크립터를, 실패하면 -1을 리턴
O_RDONLY : 읽기모드. read()호출 사용가능
O_WRONLY : 쓰기모드. write()호출 사용가능
O_RDWR : 읽기/쓰기 모드. read()/write() 호출 사용가능
O_APPEND : 데이터를 쓰면 파일 끝에 첨부된다.
ex) a.txt 파일 이미 존재.
fd = open("a.txt",O_APPEND);
텍스트를 write()하면 a.txt 내용 뒤에 해당 텍스트 추가
O_CREATE : 해당파일이 없는경우 생성하며 3.mode 는 생성할 파일의 사용권한을 나타낸다.
O_TRUNC : 파일이 이미 있는 경우 내용을 지운다.
O_EXCL : O_CREATE와 함께 사용되며, 해당 파일이 이미 있으면 오류 (-1 출력)
O_NONBLOCK : 넌블로킹 모드로 입출력 하도록 한다.
O_SYNC : write() 시스템 호출을 하면 디스크에 물리적으로 쓴 후 반환된다.
fd = open("account",O_RDONLY);
fd = open(argv[1],O_RDWR);
fd = open(argv[1],O_RDWR | O_CREATE, 6000);
fd = open("tmpfile", O_WRONLY | O_CREATE | O_TRUNC , 0600);
// tmpfile이 있으면 지우고 다시만듦 (쓰기모드)
if ((fd = open("tmpfile", O_WRONLY|O_CREAT|O_EXCL, 0666))==-1)
// tmpfile이 있으면 -1 출력, 없다면 만든다.
생성된 파일의 사용권한은 mode로 정한다.
기존 파일이 있는 경우 그 내용을 삭제하고 연다.
다음 시스템 호출과 동일
open(path, WRONLY | O_CREATE | O_TRUNC, mode);
#include <unistd.h>
int close(int fd);
// fd가 나타내는 파일을 닫는다.
닫는데 성공하면 0, 실패하면 -1리턴
#include <unistd.h>
ssize_t read ( int fd, void *buf, size_t nbytes );
파일 읽기에 성공하면 읽은 바이트 수, 파일 끝을 만나면 0,
실패하면 -1을 리턴
ssize_t write (int fd, void *buf, size_t nbytes);
#파일에 쓰기를 성공하면 실제 쓰여진 바이트 수를 리턴하고,
실패하면 -1을 리턴
• buf에 있는 nbytes 만큼의 데이터를 fd가 나타내는 파일에 쓴다
ex ) 첫번째 파일의 내용을 두번째 파일에 복사하는 코드
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2, n;
char buf[5000];
// 입력받은 파일이 두개가 아닌경우
if(argc!=3)
{
fprintf(stderr," : %s file1 file2\n",argv[0]);
exit(1);
}
// 첫번째 입력받은 파일이 없는 경우
if ((fd1 = open(argv[1], O_RDONLY)) == -1)
{
perror(argv[1]);
exit(2);
}
// 두번째 입력받은 파일이 없는 경우
if ((fd2 =open(argv[2], O_WRONLY |O_CREAT|O_TRUNC, 0644)) == -1)
{
perror(argv[2]);
exit(3);
}
fd1의 내용을 buf에 저장해서 fd2에 쓴다.
while ((n = read(fd1, buf, BUFSIZ)) > 0)
write(fd2, buf, n);
exit(0);
}
ex1) 파일 위치 이동
// 파일 시작으로 이동
lseek(fd, 0L, SEEK_SET) ;
// 파일 시작에서 100바이트 위치로 이동
lseek(fd, 100L, SEEK_SET);
// 파일 끝으로 이동
lseek(fd, 0L, SEEK_END);
ex2) 레코드 단위로 이동
// n+1 번째 레코드 시작 위치로
lseek(fd, n * sizeof(record), SEEK_SET);
// 다음 레코드 시작 위치로
lseek(fd, sizeof(record), SEEK_CUR);
// 전 레코드 시작 위치로
lseek(fd, -sizeof(record), SEEK_CUR);
ex3) 파일 끝 이후로 이동
lseek(fd,sizeof(record), SEEK_END);
ex4) 레코드 저장 예시
write(fd, &record1, sizeof(record));
write(fd, &record2, sizeof(record));
lseek(fd,sizeof(record), SEEK_END); // 파일 포인터 이동시킴
write(fd, &record3, sizeof(record));
#define MAX 24
#define START_ID 1401001
struct student{
char name[MAX];
int id;
int score;
};
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "student.h"
int main(int argc, char *argv[])
{
int fd;
struct student record;
// 입력받은 인자가 없는 경우
// argv[0]에는 프로그램 Name, 그다음부터는 인자 리스트.
if(argc <2 )
{
fprintf(stderr, "use : %s file\n", argv[0]);
exit(1);
}
// argv[1] 에 입력받은 인자(파일)를 쓰기모드로 열건데,
// 만약 해당 파일이 없으면 만들고,
// 해당파일이 있으면 -1 리턴
if( (fd = open(argv[1], O_WRONLY| O_CREAT | O_EXCL, 0640)) == -1)
{
perror(argv[1]);
exit(2);
}
// NUM NAME SCORE 출력 '%-'는 공백
printf("%-9s %-8s %-4s\n","NUM","NAME","SCORE");
// 학번 이름 점수를 3개입력받음
while( scanf("%d %s %d" , &record.id, record.name, &record.score) == 3)
{
// 파일 위치포인터를 (입력한 학번 - 1401001(시작학번) 위치로 이동
lseek(fd, (record.id - START_ID) * sizeof(record), SEEK_SET);
// 해당 위치포인터에 기록
write(fd, &record, sizeof(record));
}
// 파일닫고
close(fd);
// 종료
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "student.h"
int main(int argc, char* argv[])
{
int fd, id;
struct student record;
char c;
if(argc < 2)
{
fprintf(stderr, "use : %s file\n", argv[0]);
exit(1);
}
// 인자를 읽기모드로 열수 없다면 -1 리턴
if( (fd= open(argv[1],O_RDONLY)) == -1)
{
// 에러메세지 출력
perror(argv[1]);
exit(2);
}
do
{
printf("\n Enter the number what std : ");
// 찾고자 하는 id입력
if( scanf("%d", &id)==1 )
{
// 파일포인터를 해당하는 레코드로 이동
lseek(fd, (id-START_ID)*sizeof(record), SEEK_SET);
// 해당학생의 정보를 읽어서
if(( read(fd, &record, sizeof(record)) > 0) && record.id !=0)
{
// 프린트한다
printf("NAME : %s , NUM : %d \t, SCORE : %d \n",record.name, record.id, record.score);
}
// 해당학생의 정보를 찾을 수 없으면 메세지 출력
else
{
printf(" No record for %d\n",id);
}
}
else
{
printf("input error!\n");
}
printf("Want to continue? (Y/N)");
scanf(" %c", &c);
}while(c=='Y');
close(fd);
exit(0);
}
(1) read
(2) update
(3) write
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "student.h"
int main(int argc, char *argv[])
{
int fd, id;
char c;
struct student record;
if(argc < 2)
{
fprintf(stderr, " use %s file\n",argv[0]);
exit(1);
}
if( (fd= open(argv[1],O_RDWR)) == -1)
{
perror(argv[1]);
exit(2);
}
do
{
printf("Enter the student's student number to modify : ");
if(scanf("%d",&id) == 1)
{
// 파일 시작에서 해당 레코드의 위치로 이동
lseek(fd, (long) (id- START_ID) * sizeof(record), SEEK_SET);
// (1)번 과정 - 해당 레코드를 읽음
// -> 읽고난뒤에 파일포인터는 해당 레코드의 끝에 위치함
if( (read(fd,&record, sizeof(record)) > 0 ) && (record.id!=0))
{
printf("NUM : %8d\t NAME : %4s\t, SCORE: %4d\n",
record.id,record.name,record.score);
printf("NEW SCORE : ");
// (2)번 과정 - 해당 레코드의 점수 수정
scanf("%d" ,&record.score);
// 해당레코드의 시작부분으로 파일 포인터 이동
lseek(fd, (long) -sizeof(record), SEEK_CUR);\
// (3)번 과정 - 기록
write(fd, &record, sizeof(record));
}
else
{
printf("No %d record\n",id);
}
}
else
{
printf("Input error ! \n");
}
printf("want to continue ? : (y/n) : ");
scanf(" %c",&c);
}while(c=='Y');
close(fd);
exit(0);
}