《unix高级环境编程》文件I/O

前言:

        文件I/O可分为两类:第一类是非缓冲式的文件操作;该类型一般由系统调用,主要函数有open,write,read,lseek,close;第二类是缓冲式文件操作;该类型由标准输入输出提供操作;本文记录的是第一类文件I/O。

操作函数:

文件描述符

       内核通过文件描述符打开的文件,它是一个非负整数。通常,文件描述符0对应标准输入;文件描述符1对应标准输出;文件描述符2对应标准出错。依照POSIX,这些整数应替换为符号常量 STDIN_FILENO 、 STDOUT_FILENO 、 STDERR_FILENO ,定义在 <unistd.h> 中。

/*
 * this file is the operation about file descriptor.
 * by chenhanzhun 2014.10.21
 */

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

int main(void)
{
    printf("print the fileno:\n");
    printf("fileno of stdin =%d\n",fileno(stdin));
    printf("fileno of stdout =%d\n",fileno(stdout));
    printf("fileno of stderr =%d\n",fileno(stderr));

    return 0;
}

open函数

/*
*函数功能:打开或创建一个文件;
*返回值:若打开成功返回文件描述符,若出错则返回-1;
*/
/*
*函数原型:
*/
#include <fcntl.h>

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

/*
*参数解释:
*pathname是打开或创建的文件名称;
*oflag只能是下面三个中的一个或与其它选项组成:
*只能指定一个:O_RDONLY(只读),O_WRONLY(只写),O_RDWR(可读写)
*其它选项:
*O_APPEND	:写操作追加到文件尾
*O_CREAT	:若打开的文件不存在,则创建,需要使用第三个参数mode
*O_EXCL		:测试文件是否存在,不存在则创建此文件
*O_TRUNC	:若文件存在,且只写或读写打开,则将文件长度截取为0
*O_NOCTTY	:若文件名称pathname是终端设备,则该设备不能作为进程控制的终端
*O_NONBLOCK	:如果pathname值的是一个FIFO,一个块特殊文件或一个字符特殊文件,则此选项为文件的本次打开操作和后续的I/O操作设置非阻塞模式。
*mode是提供新建文件的权限,选项有O_CREAT时必须需要mode参数
*/
creat函数

creat函数
/*
*函数功能:创建一个新文件;
*返回值:若创建成功则返回只写文件描述符,若出错则返回-1;
*/
/*
*函数原型:
*/
#include <fcntl.h>

int creat(const char* pathname, mode_t mode);
/*等效于:open(pathname,O_WRONLY | O_CREAT | O_TRUNC, mode);*/

/*
*参数解释:
*pathname是打开或创建的文件名称;
*mode是提供新建文件的权限,选项有O_CREAT时必须需要mode参数
*/
close函数

close函数
/*
*函数功能:关闭一个已经打开的文件;同时会释放所有进程加载该文件的记录锁;
*返回值:若关闭成功返回0,若出错则返回-1;
*/
/*
*函数原型:
*/
#include <unistd.h>

int close(int filedes);

/*
*参数解释:
*filedes已打开的文件描述符;
*/
lseek函数

/*
*函数功能:当前文件偏移量;
*返回值:若成功返回新的文件偏移量,若出错则返回-1;
*/
/*
*函数原型:
*/
#include <unistd.h>

off_t lseek(int filedes, off_t offset, int whence);

/*
*参数解释:
*filedes是文件描述符;
*offset表示偏移字节数;
*whence参数有一下三种:
*SEEK_SET	:表示偏移量设置为文件开始处的offset个字节;
*SEEK_CUR	:表示偏移量设置为当前值加offset个字节;
*SEEK_END	:表示偏移量设置为文件长度加offset个字节;
*/
read函数

/*
*函数功能:读取已打开文件的数据;
*返回值:若成功返回读取的字节数,若到文件尾则返回0,若出错则返回-1;
*/
/*
*函数原型:
*/
#include <unistd.h>

ssize_t read(int filedes, void *buf, size_t nbyte);

/*
*参数解释:
*filedes是指所要读取文件的文件描述符;
*buf存储所读取数据;
*nbyte表示最多读取的字节数;
*/
write函数

/*
*函数功能:向已打开文件写入数据;
*返回值:若成功返回已写的字节数,若出错则返回-1;
*/
/*
*函数原型:
*/
#include <unistd.h>

ssize_t write(int filedes, const void *buf, size_t nbyte);

/*
*参数解释:
*filedes是指所要写入数据文件的文件描述符;
*buf存储所存储的数据;
*nbyte表示最多写入的字节数;
*/


程序测试:

#include "apue.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define buf_size 4096
#define offset 1024

int main(void)
{
    const char* src_path = "./10_22.txt";
    const char* des_path ="./test.txt";
    int  fd,fs;
    ssize_t len;
    off_t num;
    char buf[buf_size];
    fd = open(src_path,O_RDONLY);
    if(fd == -1)
        printf("open the file error.\n");
    fs = open(des_path,O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
    if(fs == -1)
        printf("open or creat the file error.\n");
    num = lseek(fd,offset,SEEK_CUR);
    printf("the offset of lseek is %d.\n",num);
    while((len = read(fd,buf,sizeof(buf))) > 0)
        write(fs,buf,len);
    close(fd);
    close(fs);
    return 0;
}

文件共享

    UNIX支持不同进程共享打开的文件。内核使用三种数据结构表示打开的文件:

  1. 进程在进程表中都有一个记录项,记录项中包含一张打开文件的描述符表。每个描述符占一项:描述符标志fd;指向一个文件表项的指针。
  2. 内核维持一张所有打开文件的文件表,每个文件表项包含文件状态标志、当前文件偏移量、指向文件v节点表项的指针。
  3. 每个打开文件有一个v节点表,每个v节点包含文件类型、操作函数指针和文件的i节点等。

        Linux将v节点和i节点实现为独立于文件系统的i节点和依赖文件系统的i节点。

       不同进程共享文件时,每个进程都有一个该文件的文件表项,指向同一个v节点表。多个文件描述符也可能指向同一个文件表项,如使用 dup 函数和 fork 后的父子进程。以下是不同进程共享同一个文件的示意图:

《unix高级环境编程》文件I/O_第1张图片


原子操作

       原子操作指由多步组成的操作,执行时要么全部执行,要么一步也不执行。
       多个进程共享同一个文件,可能造成进程对文件的连续的操作被打乱,这就需要使操作成为原子操作。如 O_APPEND 将到尾端和写入数据组成原子操作,还有 O_CREAT 和 O_EXCL 将检查文件是否存在和创建文件组成原子操作。例如:pread 和 pwrite 将偏移量和读/写组成原子操作。

#include <unistd.h>

/* 函数功能:定位并读取数据
* 返回值:成功返回读到的字节数,已到文件尾则返回0,出错返回-1 ;
*/
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
/* 函数功能:定位并写入数据
* 返回值:成功返回写入的字节数,出错返回-1 ;
*/
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

dup函数

/*
*函数功能:复制已有的文件描述符;
*返回值:若成功返回当前可用的文件描述符最小值,若出错则返回-1;
*/
/*
*函数原型:
*/
#include <unistd.h>

int dup(int filedes);

/*
*参数解释:
*filedes是指当前文件的文件描述符;
*/
dup2函数

/*
*函数功能:复制已有的文件描述符;
*返回值:若成功返回参数filedes2指定的文件描述符,如果filees2已经打开,则现将其*关闭,如果filedes1等于filedes2,则返回filedes2,不关闭;若出错则返回-1;
*/
/*
*函数原型:
*/
#include <unistd.h>

int dup2(int filedes1,int filedes2);

/*
*参数解释:
*filedes是指当前文件的文件描述符;
*/

刷新缓冲区函数

unix系统在写数据时是采用文件延迟写,但是我们可以自己刷新缓冲区,将数据写入磁盘。以下是刷新缓冲区,将数据写入磁盘的函数sync,fsync,fdatasync;

#include <unistd.h>

/* 将所有修改过的块缓冲区排入写队列,然后返回,不等待写磁盘结束 */
void sync(void);
/* 对指定文件刷新块缓冲区,等待写磁盘结束,更新文件属性
* 返回值:成功返回0,出错返回-1 */
int fsync(int fd);
/* 对指定文件刷新块缓冲区,等待写磁盘结束,不更新文件属性
* 返回值 成功返回0,出错返回-1 */
int fdatasync(int fd);

fcntl函数

/*
*函数功能:可以改变已打开文件的性质。
*函数原型:
*/
#include <unistd.h>
#include <fcntl.h>
/* 
 * 返回值:成功依赖于cmd,出错返回-1 
*/
int fcntl(int filedes, int cmd, ... /*int arg */ );
/*
*参数解释:
*filedes表示文件描述符;
*cmd参数,根据 cmd 值的不同,有以下5种功能:
*
*(1)F_DUPFD ,复制一个现有的描述符。新描述符为大于等于 arg 的最小可用值。
*(2)F_GETFD 、 F_SETFD ,获取/设置文件描述符标记。文件描述符标志只有 FD_CLOEXEC ,但一般使用0或1,分别代表 exec 时不关闭或关闭,0为默认值。
*(3)F_GETFL 、 F_SETFL ,获取/设置文件状态标志。可获取的文件状态标志见 open 函数的 flags 可取值,可设置的文件状态标志不包括访问模式位和创建模式位。
*(4)F_GETOWN 、 F_SETOWN ,获取/设置异步I/O所有权,即接收 SIGIO 和 SIGURG *信号的进程ID或进程组ID, arg 为正为进程ID, arg 为负为等于其绝对值的进程组ID。
*(5)F_GETLK 、 F_SETLK 、 F_SETLKW ,获取/设置记录锁。
*agr是指定的整数值;
*/

参考资料:

《unix高级环境编程》




你可能感兴趣的:(文件IO,Unix高级环境编程)