write(2)

#include <unistd.h>

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

open(2), creat(2), socket(2), accept(2) 등으로 생성한 file descriptor로 데이터 쓰기 또는 전송합니다. 파일에 쓰기를 하면 파일의 쓰기 또는 읽기 위치가 쓴 size만큼 뒤로 이동합니다. write(2)함수는 -1이 return되지 않는 한, 웬만하면 count만큼 정상적으로 write됩니다. O_APPEND flag로 파일을 open했다면 현재 위치가 아닌 항상 파일의 끝에 쓰기가 일어납니다.

 

 

파라미터

fd
    -  open(2), creat(2), socket(2), accept(2) 등을 통하여 정상적으로 open한 file descriptor
buf
    - 쓰기를 할 데이터 메모리 영역(buffer)
count
    - 쓸 데이터의 size (byte 수)

 

RETURN

0보다 큰 값
    - 실제로 쓴 데이터의 byte 수.
    - count와 같은 크기의 값을 return하지만, 
      count보다 작은 경우에는 signal이 발생하였거나, 쓰기 공간이 부족한경우.


0
    - 오류가 발생하지는 않았지만, 파일에 write되지 않음. (count가 0인 경우)


-1
    - 오류가 발생한 경우이며 상세한 오류는 errno에 설정됩니다.

 EAGAIN : file을 open할 때에 O_NONBLOCK flag이 설정되었으며, 쓰기 상태가 block되었을 때
 EAGAIN or EWOULDBLOCK : fd가 socket이고 socket에 O_NONBLOCK으로 설정되었으며, 
           쓰기가 block되었을 때
 EBADF  :  fd가 유효하지 않은 file descriptor임.
 EDESTADDRREQ : fd가 상대주소가 설정되지 않은 Datagram socket인 경우. 
             즉, connect로 접속된 socket이 아닌경우
 EDQUOT : 사용자별로 할당된 file system의 disk quot가 찼을 때.
 EFAULT : buf가 access할 수 없는 영역의 데이터 buffer임. 
             주로 변수를 pointer로 설정한 후에 malloc(3)하지 않은 경우
 EFBIG  : 파일의 크기가 최대 제한보다 크게 write를 하려고 할 때
 EINTR  : signal이 발생하여 interrupt됨.
 EINVAL : fd, buf, count 등의 변수가 잘못 설정된 경우. (예, count가 -값이 설정된 경우 등)
 EIO    : I/O 오류. background process에서 terminal에 대한 I/O를 시도했다든 지...
 ENOSPC : 저장하려는 공간이 부족한 경우
 EISDIR : open된 fd가 directory인 경우
 EPIPE  : pipe 또는 socket에서 상대 reading end가 close된 경우, SIGPIPE signal이 발생하여야 하는 데,
           signal이 ignore하였을 경우 errno에 EPIPE가 설정됨

 


활용 예제

 

Sample. 파일 backup 

#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

/*
* 읽을 데이터를 요청한 사이즈 만큼 읽어들임.
* 파일의 끝이면 요청한 사이즈보다 작을 수 있음.
* Signal이 발생하더라도 읽기를 처리함.
*/
int read_data(int fd, char *buffer, int buf_size)
{
    int size = 0;
    int len;

    while(1) {
        if((len = read(fd, &buffer[size], buf_size - size)) > 0) {
            size += len;
            if(size == buf_size) {
                return size;
            }
        } else if(len == 0) {
            return size;
        } else {
            if(errno == EINTR) {
                continue;
            } else {
                return -1;
            }
        }
    }
}

/*
* 저장할 데이터를 요청한 사이즈 만큼 write함
* signal이 발생하더라도 저장함
*/
int write_data(int fd, const char *buffer, int buf_size)
{
    int size = 0;
    int len;

    while(1) {
        if((len = write(fd, &buffer[size], buf_size - size)) > 0) {
            size += len;
            if(size == buf_size) {
                return size;
            }
        } else if(len == 0) {
            return size;
        } else {
            if(errno == EINTR) {
                continue;
            } else {
                return -1;
            }
        }
    }
}
 
int main(int argc, char *argv[])
{
    int  rfd;
    int  wfd;
    int  len;
    char buffer[4096];
 
    /* 파일을 읽기 전용으로 open함 */
    if((rfd = open("sample.txt", O_RDONLY)) == -1) {
        fprintf(stderr, "FILE READ OPEN ERROR: %s\n", strerror(errno));
        return 1;
    }
 
    /* 쓰기 전용으로, 파일이 없으면 생성하고, 파일이 있으면 전체데이터를 삭제하고 open함 */
    if((wfd = open("sample.txt.bak", O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) {
        fprintf(stderr, "FILE WRITE OPEN ERROR: %s\n", strerror(errno));
        return 1;
    }
 
    while(1) {
        if((len = read_data(rfd, buffer, 4096)) == -1) {
            fprintf(stderr, "READ ERROR: %s\n", strerror(errno));
            return 1;
        }
        if(len == 0) {
            break;
        }
        if((len = write_data(wfd, buffer, len)) == -1) {
            fprintf(stderr, "WRITE ERROR: %s\n", strerror(errno));
            return 1;
        }
    }
 
    close(rfd);
    close(wfd);
 
    return 0;
}

 


 

see also: System Call File I/O Library

 

블로그 이미지

사용자 자연&사람

행복한 개발자 programmer since 1995.

댓글을 달아 주세요