文件编程之系统调用

来源:互联网 发布:洛带古城知乎 编辑:程序博客网 时间:2024/05/16 06:31

1、系统调用接口

大多数文件I/O只需要用到5个函数:open、read、write、lseek 以及 close。这些函数经常被称为不带缓冲的I/O(unbuffer I/O)。术语不带缓冲的是指每个read和write都直接调用内核的一个系统调用。

创建文件函数:

#include <fcntl.h> int creat(const char *pathname, mode_t mode);

pathname是创建后的文件的绝对路径。
mode是文件的访问权限,每个文件有9个访问权限位,分为三类,见下图。

mode 数字形式 说明 S_IRWXU 7 所有者读、写和执行权限 S_IRUSR 4 所有者读权限 S_IWUSR 2 所有者写权限 S_IXUSR 1 所有者执行权限 S_IRWXG 7 组读、写和执行权限 S_IRGRP 4 组读权限 S_IWGRP 2 组写权限 S_IXGRP 1 组执行权限 S_IRWXO 7 其他读、写和执行权限 S_IROTH 4 其他读权限 S_IWOTH 2 其他写权限 S_IXOTH 1 其他执行权限

打开文件函数:

#include <fcntl.h>  int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);

open函数返回一个文件描述符fd,用于指定打开的文件流。 flags是打开标志,可由以下常量进行“或”运算构成flags参数。
注意:5个常量必须指定一个且只能指定一个!!

必选常量 说明 O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 读、写打开 O_EXEC 只执行打开 O_SEARCH 只搜索打开 可选常量 说明 O_APPEND 每次写时都追加到文件的尾端 O_CLOEXEC 把FD_CLOEXEC常量设置为文件描述符标志 O_CREAT 若此文件不存在则创建它。使用此选项时,open函数必须同时说明第三个参数mode O_DIRECTORY 如果path引用的不是目录,则出错 O_EXEL 如果同时指定了O_CREAT,而文件已经存在,则出错 O_NOCTTY 如果path引用的是终端设备,则不讲该设备分配作为此进程的控制终端 O_NOFOLLOW 如果path应用的是一个符号链接,则出错 O_NONBLOCK 如果path引用的是一个FIFO、一个块特殊文件或一个字符特殊文件,则设置此文件本次打开操作跟后续的I/O操作为非阻塞方式 O_SYNC 使每次write等待物理I/O操作完成 O_TRUNC 如果此文件存在,而且为只写或读写成功打开,则将其长度截断为0 O_TTY_INIT 如果打开一个还未打开的终端设备,设置非标准termios参数值

如果使用了O_CREAT标志,则使用的函数是:

int open(const char *pathname, int flags, mode_t mode);

例如(等价于 creat 函数):

open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);

读文件函数

#include <unistd.h>  ssize_t read(int fd,void *buf,size_t nbytes);  

从文件描述符fd指定的文件中读取 nbytes 个字节到 buf 所指向的缓冲区中,返回值为实际读取的字节数。


写文件函数

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

将 buf 指向的缓冲区内容写向文件描述符 fd 指定的文件中,返回值为实际写入文件的字节数。对于普通文件,写操作从文件的当前偏移量处开始,如果打开该文件时,指定了O_APPEND选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处。


定位函数

#include <unistd.h>  off_t lseek(int fd,off_t offset,int whence);  

对参数offset的解释与参数whence的值有关。

whence 说明 SEEK_SET 则将该文件的偏移量设置为距距文件开始处offset个字节 SEEK_CUR 则将该文件的偏移量设置为其当前值加offset,offset可为正或负 SEEK_END 则将该文件的偏移量设置为文件长度加offset,offset可正可负

若lseek成功执行,则返回新的文件偏移量,为此可以用下列方式确定打开文件的当前偏移量


关闭文件函数

#include <unistd.h>  int close(int fd);  

2、基于系统调用的文件拷贝demo

#include <apue.h>#include <fcntl.h>#define BUFSIZE 1024int copy(int psrc_fd, int pdst_fd);int main(int argc, const char *argv[]){    int src_fd;    int dst_fd;    if (argc != 3){        fprintf(stderr, "usage: %s src_file dst_file", argv[0]);        exit(1);    }    /* 打开源文件 */    if ((src_fd = open(argv[1], O_RDONLY)) == -1){        fprintf(stderr, "open %s error !", argv[1]);        exit(1);    }    /* 创建目的文件 */    if ((dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0751)) == -1){        fprintf(stderr, "open %s error !", argv[2]);        exit(1);    }    /* 复制源文件到目的文件 */    copy(src_fd, dst_fd);    /* 关闭文件 */    close(src_fd);    close(dst_fd);    exit(0);}int copy(int psrc_fd, int pdst_fd){    ssize_t bytes_read;    ssize_t bytes_write;    char buf[BUFSIZE];    char *ptr = NULL;    /* 以下是经典的拷贝文件代码 */    while (bytes_read = read(psrc_fd, buf, BUFSIZE)){        /* 一个致命的错误发生了,跳出循环 */        if ((bytes_read == -1) && (errno != EINTR)){            fprintf(stderr, "Read data error from src_file !");            break;        }        else if (bytes_read > 0){            ptr = buf;            while (bytes_write = write(pdst_fd, ptr, bytes_read)){                /* 一个致命的错误发生了,跳出循环 */                if ((bytes_write == -1) && (errno != EINTR)){                    fprintf(stderr, "Write data error to dst_file !");                    break;                }                /* 将所有读出的字节全部写入文件,跳出循环,继续读数据 */                else if (bytes_write == bytes_read){                    break;                }                /* 若只写了一部分,继续写入文件 */                else if (bytes_write > 0){                    ptr += bytes_write;           //指向未读取数据的指针的首地址                    bytes_read -= bytes_write;    //计算剩下未读的字节数                }            }        }    }    return 0;}
原创粉丝点击