AUPE学习第三章------文件I/O1

3.6lseek函数

lseek函数用于当打开一个文件时与其关联的”当前文件偏移量“的操作相关。
函数格式:
off_t     lseek(int   fileds,  off_t   offset,   int   whence);
若成功则返回新的文件偏移,若出错则返回-1.。
对参数offset的解释与参数whence的值相关。
whence==SEEK_SET          距文件开始处offset个字节。
whence==SEEK_CUR         文件偏移量设置为当前offset
whence==SEEK_END         偏移量为文件长度加上offset。

下面的程序测试标准输入能否被设置位移量lseektest.c:
#include <sys/types.h>
#include "ourhdr.h"
int main(void)
{
    if (lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
        printf("cannot seek\n");
    else
        printf("seek ok\n");
    exit(0);
}

运行结果如下:
[root@localhost apue]# gcc -o lseektest.out lseektest.c 
[root@localhost apue]# ./lseektest.out 
cannot seek
[root@localhost apue]# ./lseektest.out </etc/motd
seek ok
[root@localhost apue]# cat < /etc/motd | ./lseektest.out 
cannot seek
lseek函数只将文件位移量记录在内核中,它并不引起任何I/O操作。然后该位移量用于下一个读或者写操作。

下面的程序创建一个具有空洞的文件:
fseekcreate.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "ourhdr.h"
#include "error.c"

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

int main(void)
{
    int fd;
    if ((fd = creat("file.hole", FILE_MODE)) < 0)
    {
        err_sys("creat error");
    }
    if (write(fd, buf1, 10) != 10)
        err_sys("buf1 write error");
    if (lseek(fd, 40, SEEK_SET) == -1)
        err_sys("lseek error");
    if (write(fd,buf2,10) != 10)
        err_sys("buf2 write error");
    exit(0);
}
文件中间30个未写字节都被读成0。

运行结果如下:
[root@localhost apue]# gcc -o fseekcreate.out fseekcreate.c 
[root@localhost apue]# ./fseekcreate.out 
[root@localhost apue]# ls -l file.hole 
-rw-r--r-- 1 root root 50 12-26 19:54 file.hole
[root@localhost apue]# od -c file.hole 
0000000   a   b   c   d   e   f   g   h   i   j  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040  \0  \0  \0  \0  \0  \0  \0  \0   A   B   C   D   E   F   G   H
0000060   I   J
0000062

3.7 read函数

用read函数从打开的文件中读取数据。
ssize_t    read(int    filedes,     void    *buff,    size_t  nbytes)
返回读到的字节数,如果已经到了文件尾,返回0,若出错返回-1。
从终端设备读取时,通常一次最多读取一行。
读操作从文件的当前位移量开始。

3.8write函数

用write函数向打开文件写数据。
ssize_t    write(int   fileds,   const   void  *buff,   size_t   nbytes)
若成功读取返回已写的字节数,失败返回-1。
对于普通文件,写操作从文件的当前位移量处开始。

3.9  I/O的效率

下面的程序使用read和write函数来复制一个文件:

说明:所有的UNIX shell都提供一种方法,它在标准输入上打开一个文件用于读(STDIN_FILENO)。在标准输出上创建一个文件用于写(STDOUT__FILENO)。
stdinout.c:
#include "ourhdr.h"
#include "error.c"

#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)
            err_sys("write error");
    if (n <0)
        err_sys("read error");
    exit(0);
}

运行结果如下:
[root@localhost apue]# gcc -o stdinout.out stdinout.c 
[root@localhost apue]# ./stdinout.out 
hello
hello
nihao
nihao
BUFFSIZE一般设置为8192处,系统CPU时间出现最小值。

3.10文件共享

UNIX支持在不同进程之间打开共享文件。
内核用三个数据结构用于文件共享操作实现:
    每个进程在进程表中有一个记录项,每个记录项中有一张打开文件的描述符表。
    内核为所有打开的文件维持一张文件表。
    每个打开的文件或者设备都有一个V节点结构。
每个进程可以打开多个文件,每个文件对应一个文件表项。多个进程可以打开一个文件。

3.11原子操作

3.11.1添加至一个文件

在写入一个文件的时候,"定位档到文件结尾处,然后写"。这个操作不能被其他操作中断,这就是原子操作。
UNIX实现原子操作的方法是在打开文件时设置O_APPEND标志。
原子操作:指的是由多部组成的操作,该操作原子地执行完所有步或者一步也不执行。

3.12dup和dup2函数

下面两个函数都可用于复制一个现存的文件描述符:
int    dup(int    filedes)
int    dup2(int   filedes,   int    filedes2)
两函数都是若成功返回新的文件描述符,若错误返回-1。
由dup返回的新文件描述符一定是当前可用文件描述符中最小的整数。dup2则可用用filedes2参数指定新文件描述符的数值。

3.13fcntl函数

fcntl函数可以改变已经打开的文件的性质。
int    fcntl(int    filedes,   int   cmd, ...)
返回:若成功,则依赖于cmd,如出错则-1。
F_GETFL可以用于获取文件状态标志作为函数的返回值。
fcntl的返回值与命令有关,如果出错,所有命令都返回-1。

下面的程序对于指定的文件状态描述符打印文件标志:
fcontltest.c:
#include <sys/types.h>
#include <fcntl.h>
#include "ourhdr.h"
#include "error.c"

int main(int argc, char *argv[])
{
    int accmode, val;
    if (argc != 2)
        err_quit("usage:a.out <descriptor#>");
    if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
        err_sys("fcntl error for fd %d", atoi(argv[1]));

    accmode = val & O_ACCMODE;
    if (accmode == O_RDONLY)       printf("read only");
    else if (accmode == O_WRONLY)  printf("write only");
    else if (accmode == O_RDWR)    printf("read write");
    else err_dump("unknow access mode");

    if (val & O_APPEND)            printf(", append");
    if (val & O_NONBLOCK)          printf(", nonblocking");
    #if !defined(_POSIX_SOURCE) && defined(O_SYNC)
    if (val & O_SYNC)              printf(", synchronous writes");
    #endif
    putchar('\n');
    exit(0);
}
说明:
如果第二个参数是F_GETFL,则设置并返回文件状态标识符为第一个参数的值。
O_ACCMODE<0003>:读写文件操作时,用于取出flag的低2位
atoi函数的功能是把字符串转换为整数。
运行结果:
[root@localhost apue]# vim fcontltest.c 
[root@localhost apue]# gcc -o fcontltest.out fcontltest.c 
[root@localhost apue]# ./fcontltest.out 0 < /dev/tty
read only
[root@localhost apue]# ./fcontltest.out 1> temp.foo
usage:a.out <descriptor#>
[root@localhost apue]# ./fcontltest.out 1 > temp.foo
[root@localhost apue]# cat temp.foo 
write only
[root@localhost apue]# ./fcontltest.out 2  2> > temp.foo
bash: syntax error near unexpected token `>'
[root@localhost apue]# ./fcontltest.out 2  2>> temp.foo
write only, append
[root@localhost apue]# ./fcontltest.out 5  5>> temp.foo
write only, append
[root@localhost apue]# ./fcontltest.out 5  5<> temp.foo
read write
[root@localhost apue]# cat temp.foo 
write only













  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值