unix环境高级编程笔记(2)-- 文件I/O之不带缓冲的I/O

1 引言

  不带缓冲区的I/O(unbuffered I/o)是指每个read 和 write 都调用内核中的一个系统调用,这些不带缓冲区的I/O 不是ISO C 的组成部分。



2 文件描述符

  每个打开的文件都通过文件描述符引用,文件描述符是一个非负整数。open 和 create 函数返回的文件描述符供 read write 和 close 使用。

unix中文件描述符0与标准输入相关联,文件描述符1与标准输出相关联,文件描述符2与标准出错输出相关联。



3 不带缓冲区的I/O函数

下面介绍6个常用的I/O函数 open,creat,read,write,lseek,close.

3.1 open函数

#include <fcntl.h>
int open(const char *pathname,int oflag,.../* mode_t mode*/)
成功返回文件描述符,出错返回-1 open函数返回的文件描述符一定是最小的未用的描述符数值。

对于open而言,只有创建新文件的时候才会用到第三个参数 mode

pathname是打开或创建文件的名字,oflag说明此函数的选项,由以下常量进行按位或构成oflag(这些常量定义在<fcntl.h>中)

必选:且只能选一个

O_RDONLY                   只读打开

O_WRONLY                  只写打开

O_RDWR                      读 写打开

可选:

  O_APPEND      每次写操作都写在文件的尾端

  O_CREAT          若此文件不存在则创建它,使用此选项时,必须指定第三个参数 mode 用于指定该文件的访问位权限。

  O_EXCL        如果同时指定了O_CREAT,若此文件存在则出错返回 -1 用于测试一个文件是否存在,测试和创建新文件是一个原子操作

  O_TRUNC        如果此文件存在,而且为只写或者读写成功打开,则此文件截断为0.

  O_NOCTTY      如果pathname是终端设备,则不将此设备分配作为进程的控制终端

  O_NONBLOCK      如果pathname是一个FIFO,一个块特使文件,一个字符特殊文件,则此选项为本次打开操作及后续的I/O操作设置为非阻塞模式

下面三个标志也是可选的:

  O_DSYNC         每次写等待物理I/O完成,如果写操作并不影响读取刚刚写入的数据,则不等待文件的属性更新。

  O_RSYNC       是每一个以文件描述符作为参数的read操作等待,直至任何对文件同一部分进行的未决写操作完成。

  O_SYNC         使每次write都等待物理I/O操作完成,

O_DSYNC 在重写现有部分内容时,文件时间属性不会同步更新,而O_SYNC每次write操作都会在返回前等新文件时间。

3.2 creat函数

#include <fcntl.h>
int creat(const char *pathname,mode_t mode)
若成功返回以只写方式打开的文件描述符,失败返回 -1

现在可以用以下方式调用open来代替creat

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

3.3 close函数

#include <fcntl.h>
int close(int filedes);
若成功返回0,出错返回 -1 ;

当一个进程终止时,会自动关闭所有打开的文件描述符,所以很多程序利用这一功能不显示调用close关闭文件描述符;

3.4 lseek函数

#include <unistd.h>
off_t lseek(int filedes,off_t offset,int where);
成功返回新的文件偏移量,出错返回 -1 ;

offset 的含义与where的选择有关:

  SEEK_SET    将文件偏移量设定为距文件开始处offset个字节;

  SEEK_CUR    将文件偏移量设定为当前值加上offset (offset可正可负);

  SEEK_END    将文件偏移量设定为文件长度加上offset(offset可正可负);

调用lseek(fd,0,SEEK_CUR)可以确定打开文件的当前偏移值。也可以用此来测试文件是否可以设置偏移量。若fd为管道,FIFO,和网络套接字 则返回 -1,并将errno设为ESPIPE;

#include <stdio.h>
#include <unistd.h>
int main()
{
    if(lseek(STDIN_FILENO,0,SEEK_CUR) == -1)
        printf("connot seek\n");
    else
        printf("seek OK\n");
    return 0;
}

编译该程序,运行。

[email protected]:/program# ./3-1 < /etc/motd
seek OK
[email protected]:/program# cat < /etc/motd | ./3-1
connot seek

3.4.1 具有空洞的文件

当文件偏移量大于当前文件长度时候,就在文件中形成一个空洞,位于文件中但没有写过的字节都被读为0。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define FILE_MODE S_IRUSR | S_IWUSR | S_IXUSR
int main()
{
    char buf1[] = "abcde";
    char buf2[] = "ABCDE";
    int fd;
    if((fd = creat("foo",FILE_MODE)) < 0)
    {
        printf("creat file error\n");
        return -1;
    }
    if(write(fd,buf1,5) != 5)
    {
        printf("write error\n");
        return -1;
    }
    if(lseek(fd,1024,SEEK_SET) == -1)
    {
        printf("seek error\n");
        return -1;
    }
    if(write(fd,buf2,5) != 5)
    {
        printf("write error\n");
        return -1;
    }
    return 0;
}
查看文件大小[email protected]:/program# ls -l foo
-rwx------ 1 root root 1029 Nov  2 20:48 foo
[email protected]:/program#
查看文件内容

[email protected]:/program# od -c foo
0000000   a   b   c   d   e  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
0002000   A   B   C   D   E
0002005
[email protected]:/program#

可以看出文件中未写的字节全部填充为0.

3.5 read函数

#include <unistd.h>
ssize_t read(int filedes,void *buf,ssize_t nbytes);
若成功返回读取到的字节数,若已到达文件末尾返回0,出错返回-1;

读操作从当前的文件偏移量开始,在read返回前,文件偏移量将增加实际读取的字节数。实际读取的字节数可能比nbytes小。

3.6 write函数

#include <unistd.h>
ssize_t write(int filedes,const void *buf,size_t nbytes);
若成功返回写入的字节数,一般返回值等于nbytes,出错返回 -1;

对于普通文件,write操作从文件的当前偏移量处开始,如果打开文件时制定了O_APPEND,则将文件偏移量设置为文件的结尾处,成功写之后,文件偏移量将增加写的字节数。

/*将标准输入复制到标准输出*/#include <stdio.h>
#include <unistd.h>
#define BUFFSIZE 1024
int main()
{
    int n;
    char buf[BUFFSIZE];
    while((n = read(STDIN_FILENO,buf,BUFFSIZE)) > 0)
        if(write(STDOUT_FILENO,buf,n) != n)
        {
            printf("write error\n");
            return -1;
        }
    if(n < 0)
        printf("read error\n");
    return 0;
}
[email protected]:/program# ./3-3
hello world!
hello world!
时间: 2024-12-31 03:31:27

unix环境高级编程笔记(2)-- 文件I/O之不带缓冲的I/O的相关文章

UNIX环境高级编程笔记之文件I/O

一.看图说话 一图胜过千言,看图! 二.唠一唠 在写之前,先唠几句,<UNIX环境高级编程>,简称APUE,这本书简直是本神书,像我这种小白,基本上每看完一章都是“哇”这种很吃惊的表情.其实大概三年前,那会大三,我就买了这本书,也看过一些,但好像没有留下什么印象,今天再看,依然觉得像新的一样.很大的原因我想是一直以来都在用windows(用windows做开发为什么学不到真正的技术,我想大家都懂的),当然知识结构不完整,学习能力这些就不说了.所以,对于那些致力于想在Linux下做开发的人来说,

4.28 UNIX环境高级编程 笔记

int dup(int filedes); int dup2(int filedes,int filedes2); 这两个函数都可以实现复制一个现存的文件描述符,但是dup一定返回当前可用最小文件描述符,dup2可以用filedes2参数指定新描述符数值.如果filedes2已经打开,则先将其关闭.如果filedes等于filedes2,则返回filedes2而不关闭. 这些函数返回的新文件描述符与参数参数filesdes共享同一个文件表项. 图3 执行dup之后的内核数据结构 dup2是原子操

unix环境高级编程笔记(4)—— 文件和目录(1)

1 引言 本文将描述文件系统的一些特征和文件的性质,从stat函数开始,逐个讲解stat结构的成员以了解文件的属性. 2 stat,fstat 和 lstat函数 #include <sys/stat.h> int stat(const char *restrict pathname,struct stat *restrict buf); int fstat(int filedes,struct stat *restrict buf); int lstat(const char *restri

《UNIX环境高级编程》---4文件和目录

文件和目录 一. stat 结构和权限相关 四个stat函数:返回文件或者目录的信息结构: #include<sys/stat.h> int stat(const char * restrict pathname, struct stat*restrict buf); int fstat(int fd, struct stat* buf); int lstat(const char* restrict pathname,struct stat *restrict buf); int fstat

unix环境高级编程笔记(3)-- 文件I/O(2)

本文讨论如何在多个进程间共享文件,以及所涉及的内核数据结构.然后会介绍dup,dup2,fcntl等函数的使用. 1 数据结构 内核使用三种数据结构表示打开的文件: (1)每个进程在进程表中都有一个记录项,记录项中有一张打开文件文件描述符表,每项包括: a )文件描述符标志(close_on_exec) b)指向一个文件表的指针 (2)内核为所有打开的文件维护一张文件表,每个文件表项包括: a)文件状态标志(读 写  添加  同步和非阻塞) b)  当前文件偏移量 c)  指向v节点的指针 (3

unix环境高级编程笔记(5)—— 文件和目录(2)

1 文件截短 有时我们需要把文件尾端处截去一些数据以缩短文件,将一个文件清0是一个特例.在打开文件时使用O_TRUNC标志可以做到这一点. #include <unistd.h> int truncate(const char *pathname,off_t length); int ftruncate(int filedes,off_t length); 成功返回0,出错返回-1. 如果length 小于文件长度,则使文件长度截断至length,剩下的不可访问.如果length大于文件长度,

unix环境高级编程笔记(6)—— 文件和目录(3)

这一节主要是讲目录的操作,涉及创建目录.删除目录.读取目录等 1 mkdir 和 rmdir 用mkdir创建目录,用rmdir删除目录. #include <sys/stat.h> int mkdir(const char *pathname,mode_t mode); 成功返回0,出错返回-1. 此函数创建一个新的空目录,. 和.. 自动创建,文件访问权限mode由进程的文件模式创建屏蔽字进行修改.(必须指定一个执行权限位) #include <unistd.h> int rm

《UNIX环境高级编程》---3.文件I/O

一.打开.创建文件.关闭文件 文件描述符:一个非负整数,范围是0~OPEN_MAX-1.内核用它来标识进程正在访问的文件.当进程创建时,默认为它打开了3个文件描述符,它们都链接向终端: 0: 标准输入 1: 标准输出 2: 标准错误输出 通常我们应该使用STDIN_FILENO,STDOUT_FILENO和 STDERR_FILENO来替代这三个幻数,从而提高可读性.这三个常量位于<unistd.h>中. 2. open和openat函数:打开文件 ``` #include<fcntl.

UNIX环境高级编程笔记之高级I/O

本章说明了很多高级I/O功能: 非阻塞I/O——发一个I/O操作,不使其阻塞,记录锁,STREAMS机制 I/O多路转接——select和poll函数 readv和writev函数,以及存储映射I/O(mmap函数)