文件I/O

1、文件描述符
    <unistd.h>
    STDIN_FILENO        0
    STDOUT_FILENO        1
    STDERR_FILENO        2

    范围    0 - OPEN_MAX

2、open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

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

    /*返回:成功为文件描述符,出错为-1*/
oflag:    O_RDONLY    O_WRONLY    O_RDWR    /*三选一*/
    
    O_APPEND    O_CREAT        O_EXCL        O_SYNC
    O_TRUNC        O_NOCTTY    O_NONBLOCK        /*可选*/

由open返回的文件描述符一定是最小的未用描述符数字.


3、creat

#include <sys/types.h>
#include <sys/stat.h>'
#include <fcntl.h>

int creat(const char *pathname, mode_t mode)

/*返回:成功为只写打开的文件描述符,出错为-1*/

等效于:
open( pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);


4、close

#include <unistd.h>

int close(int filedes);

/*返回:成功为0,出错为-1*/

5、lseek

#include <sys/types.h>
#include <unistd.h>

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

/*返回:成功为新的文件位移,出错为-1*/

whence参数:    SEEK_SET
        SEEK_CUR
        SEEK_END

eg:
/*
 *测试标准输入能否被设置位移量
 */

#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
        printf("cannot seek\n");
    else
        printf("seek ok\n");
    return 0;
}

note:
    通常,文件的当前位移量应当是一个非负整数,但是,某些设备也可能允许负的位移量。但对于普通文件,则其位移量必须是非负值。因为位移量可能是负值,所以在比较lseek的返回值时应当谨慎,不要测试它是否小于0,而要测试它是否等于-1。
    lseek仅将当前的文件位移量记录在内核内,它并不引起任何I/O操作。然后,该位移量用于下一个读或写操作。

eg:
/*
 *创建一个具有空洞的文件
 */

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

#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";

int main(void)
{
    int fd;        /*文件描述符*/
    
    if((fd = creat("file.hole",FILE_MODE)) < 0)
        printf("creat error\n");
    if(write(fd, buf1, 10) != 10)
        printf("buf1 write error\n");
    /*当前文件位移量为10*/
    
    if(lseek(fd, 40, SEEK_SET) == -1)
        printf("lseek error\n");
    /*现在当前文件位移量为40*/

    if(write(fd, buf2, 10) != 10)
        printf("buf2 write error");
    /*现在当前文件位移量为50*/
    
    return 0;
}


6、read

#include <unistd.h>

ssize_t read(int filedes, void *buff, size_t nbytes);

/*返回:读到的字节数,若已到文件尾为0, 若出错为-1*/

note:
    读操作从文件的当前位移量处开始,在成功返回前,该位移量增加实际读到的字节数。


7、write

#include <unistd.h>

ssize_t write(int filedes, const void *buff, size_t nbytes);

/*返回:若成功为已写的字节数,若出错为-1*/


8、I/O的效率

eg:
/*
 *将标准输入复制到标准输出
 */

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

#define BUFFSIZE 8192

int main(void)
{
    int n;
    char buf[BUFFSIZE];
    
    while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
        if(write(STDOUT_FILENO, buf, n) != n)
            printf("write error");
    if(filedes < 0)
        printf("read error");

    return 0;
}


9、文件共享

    UNIX支持在不同进程间共享打开文件。
    内核使用了三种数据结构,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。



A 进程表项        B 文件表        C v节点表

 fd0:            文件状态标志        v节点信息
  fd1:            当前文件位移量        i节点信息
  fd2:            v节点指针        当前文件长度
  .......

10、原子操作

思考:
    多进程操作下,问题"定位到文件尾端处,然后写",在早期UNIX系统中,会出现写操作覆盖的错误。解决问题的方法就是使这两个操作对于其他进程而言成为一个原子操作。任何一个要求多于 1个函数调用的操作都不能成为原子操作,因为在两个函数调用之间,内核可能会临时挂起进程。

    一般而言,原子操作指的是由多步组成的操作。如果该操作原子地执行,则或者执行完所有步,或者一步也不执行,不可能只执行所有步的一个子集。



11、dup 和 dup2

#include <unistd.h>
int dup(int filedes);
int dup2(int filedes, int filedes2);

/*返回:若成功为新的文件描述符,若出错为-1*/

    由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。用dup2则可以用filedes2参数指定新描述符的数值。如果filedes2已经打开,则先将其关闭。如若filedes等于filedes2,则dup2返回filedes2,而不关闭它。


12、fcntl

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int fcntl(int filedes, int cmd, .../* int arg */);

/*返回:若成功则依赖于cmd, 若出错为-1*/

fcntl函数有五种功能:
    复制一个现存的描述符 (cmd = F_DUPFD)
    获得/设置文件描述符标记 (cmd = F_GETFD 或 F_SETFD)
    获得/设置文件状态标志 (cmd = F_GETFL 或 F_SETFL)
    获得/设置异步I/O有权 (cmd = GETOWN 或 SETOWN)
    获得/设置记录锁 (cmd = F_GETLK, F_SETLK 或 F_SETLKW)


13、ioctl

#include <unistd.h.>
#include <sys/ioctl.h>

int ioctl(int filedes, int request,...);


14 /dev/fd
    







你可能感兴趣的:(编程,c,linux,unix)