LINUX系统编程--2 系统IO

二 系统IO

  • 二 系统IO(文件IO)
    • 1 文件描述符的概念
    • 2 文件IO的操作
    • 3 标准IO与文件IO的区别
    • 4 IO的效率问题
    • 5 文件共享
    • 6 dup和dup2
    • 7 一点设计模式
    • 8 同步sync、fsync
    • 9 fcntl函数
    • 10 ioctl函数
    • 11 /dev/fd目录

二 系统IO(文件IO)

贯穿文件IO的是文件描述符,而贯穿标准IO的是FILE指针(也可以说是流)

本章内容:
文件描述符的概念
文件IO的操作:open close read write lseek
文件IO与标准IO的区别
IO的效率问题
文件共享问题
原子操作
程序中得到重定向:dup和dup2
同步:sync、fsync
fcntl();
ioctl();
/dev/fd/目录

1 文件描述符的概念

见P60

理清PCB进程控制块,进程表项,文件描述符,文件表项,V节点,i节点之间的关系

2 文件IO的操作

open需要注意的是:

1、要包含

#include
#include
#include

2、open的时候,与标准IO的打开方式的联系为:
在这里插入图片描述
其他的以此类推!

3、open函数的函数原型在man有两种形式,一种是有两个参数,一个是有三个参数。

当用open创建一个文件时,就要使用三个参数的原型形式,第三个参数来确定创建的文件的权限。
(这里需要注意的是,C中没有函数重载,这里的open是变参函数!变参函数可以传多个参数,没有固定。常见的printf等都是变参函数)

第三个参数依然是与umask相结合从而确立所创建文件的权限!

read/write/lseek

//mycpy.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define BUFFSIZE 1024
//代码说明
// copy 一个文件到另外一个文件

int main(int argc,char **argv)
{
    int sfd,dfd;
    int len;
    int ret;
    int pos;
    char * buf[BUFFSIZE];
    if(argc<3)
    {
        fprintf(stderr,"Uage:too less arg");
        exit(1);
    }
    sfd=open(argv[1],O_RDONLY);
    if(sfd<0)
    {
        perror("open error1");
        exit(1);
    }
    dfd=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0600);
    if(dfd<0)
    {   
        close(sfd);   //注意这个地方!!!
        perror("open error");
        exit(1);
    }

    while(1)
    {
        len =read(sfd,buf,BUFFSIZE);
        if(len<0)
        {
            perror("read error");
            break;
        }
        if(len==0)
        {
            break;
        }

        pos=0;
        while(len>0)  //防止写的字节小于读到的字节数,解决方法,继续读!
        {
            ret=write(dfd,buf+pos,len);

            if(ret<0)
            {
             perror("write error");
                exit(1);
            }
            pos+=ret;
            len-=ret;
        }
    }

    close(dfd);
    close(sfd);
    exit(0);
}

3 标准IO与文件IO的区别

区别:响应速度上(文件IO快),吞吐量上(标准IO大)
一个问题:如何使一个程序变快?

两者区别主要是缓冲区的存在!!

尽量使用标准IO!!

标准IO与文件IO两者不可混用!
补充两个函数:fileno和fdopen,可以将流和文件描述符相互转换。即使可以相互转换,但是两者还是不能混用!

4 IO的效率问题

LINUX系统编程--2 系统IO_第1张图片

一个小实验:
在执行的程序前加一个time,可以得到程序运行的时间。第一行是真实时间,第二行是在用户区执行的时间,第三行是系统调用花的时间。

实验:
在mycpy.c程序中更换缓冲区buf的大小,BUFSIZE从128到16M,依次增大2倍,做出一张表,来查看系统所消耗的时间的不同!找到性能最大的拐点以及BUFSIZE多大程序会出问题(段错误)。

5 文件共享

文件共享指的是:多个任务共同操作一个文件或者协同完成任务。

面试:写程序删除一个文件的第十行。
思路1:在同一个程序中找那个打开一个文件两次,得到两个不一样的文件描述符,分别定位到11行和10行。然后进行循环读写(读写操作会自动更新文件的偏移量)。
这里需要注意的是,一个文件打开一个文件两次,得到的两个文件描述符指向的文件表项是不一样的,也就是说,他们有各自的文件偏移量,不会共享(这是与dup的区别);但是因为打开的是同一个文件,他们的指向的V节点一定是一样的。(详见 P61)
LINUX系统编程--2 系统IO_第2张图片
思路二:多进程和多线程

补充函数:truncate和ftruncate,进行文件的截断。

6 dup和dup2

dup和dup2
第一个需要注意的是,这是赋值文件描述符的两个函数,复制后,两个文件描述符的指向的文件表项是相同的,也就是说共享文件偏移量。

第二个需要注意的是,dup2的一些小细节,见man dup2

7 一点设计模式

写程序,注意三个地方
1 特别注意内存泄漏
2 特别注意数据溢出、越界
3 要有宏观编程思想,把main函数当做是编写模块。因此编写完要使使用到的资源回归到原来的位置(最简单的例子是,程序中我们自行关闭的标准输入输出,要重新打开)。

8 同步sync、fsync

同步内核层面的缓存和磁盘。注意这里是指的是内核层面的。与fflush是不一样的。

9 fcntl函数

管家函数,参数不一样,返回值也不一样
文件描述符所变得魔术几乎都来源于该函数

10 ioctl函数

设备相关的内容
(一切皆文件设计思想的牺牲者)

11 /dev/fd目录

是一个虚目录,显示的是当前进程的文件描述符信息,谁打开这个目录,看到的就是这个进程的文件描述符信息。

比如:
ls -l /dev/fd ,得到的就是ls的这个进程的文件描述符信息;
在程序中打开这个文件,就会得到程序运行起来的这个进程的。

你可能感兴趣的:(LINUX系统编程,linux)