Linux下基础I/O

Lin9ux下的基础I/O

C语言阶段

  1. 在学习C语言的时候,我们要实现程序的I/O操作,需要调用fopen()和fclose来打开和关闭文件,fopen()成功返回FILE*的文件指针,
  2. 利用fread和fwrite函数来进行文件的读写操作。当然我们还学过fseek重置文件指针,ftell,rewind等函数
  3. 我们还知道,C会默认打开流,stdin,stdout,stderr,并且这三个流都是FILE*类型的,即文件指针。

系统编程阶段

  1. 当我们进入系统编程之后,我们可以同样的调用系统接口,来实现I/O操作。
    系统接口

  2. open
    int open(const char*pathname, int flags);
    int open(const char* pathname,int flags,mode_t mode)
    pathnamm:要打开文件名称
    flag:O_RDONLY(只读),O_WRONLY(只写),O_RDWR(可读可写),O_CREAT(文件不存在则创建之,并且要加上mode权限)
    3.write
    ssize_t write(int fd, const void *buf, size_t count);
    fd:对应操纵文件的文件描述符,
    buf:源数据存放内存
    count:一次写入多少个字节
    返回值:实际写入字节数

  3. read
    ssize_t read(int fd, void *buf, size_t count);
    fd:对应文件的文件描述符;
    buf:写到的目的内存;
    count:一次写入的字节数;
    返回值:实际读取的字节数

  4. close
    int close(int fd);
    关闭对应文件描述符为fd的文件。
  5. 我们知道,c提供的f#类函数都是库函数,调用成功返回文件指针,而open,close,write,read属于系统调用接口,在讲操作系统的作用的时候,讲过下面这张图。
    Linux下基础I/O_第1张图片
  6. 不难看出,c库函数都是封装了系统调用的接口,方便二次开发。我们又知道linux下一个进程的PCB中有files*的一个字段,描述一个进程打开文件的情况,而这个指针指向一个files_struct的结构体表,这个表中最重要的就是保护一个指针数组,每个数组元素都指向打开的文件,我们通常就利用数组的下标来操纵对应位置的元素,我们把这里的下标称之为文件描述符,我们都知道数组下标从0开始的,所以每一个进程都默认打开0,1,2三个文件描述符表示的文件,分别代表标准输入,标准输出,标准出错。如下图Linux下基础I/O_第2张图片
    这里我们就来练习一下这几个函数:
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 int main()
  8 {        
  9          
 10     int fd=open("myfile",O_RDWR|O_CREAT,0644);
 11     if(fd<0)
 12     {    
 13         perror("open");
 14         return -1;
 15     }    
 16     int count=5;
 17     char *buf="hello,world\n";
 18     while(count--)
 19     {    
 20 write(fd,buf,strlen(buf));
 21     }    
 22     char buf2[1024];
 23     while(1)
 24     {    
 25          
 26         ssize_t s=read(fd,buf2,strlen(buf)-1);                                                                                                                                                               
 27         if(s>0)
 28         {
 29             printf("myfile if :%s\n",buf2);
 30         }
 31         else
 32         {
 33             break;
 34         }
 35     }    
 36     close (fd);
 37     return 0;
  • 既然现在我们了解了系统编程的I/O函数,已经文件描述符的概念,我们就知道,一个进程默认会打开0,1,2三个分别代表标准输入,标准输出,标准出错的文件描述符,而系统默认的输出就是屏幕,默认的输入就是键盘,如果讲原本输出到屏幕的数据输出到指定地方,这就叫做输出重定向.就拿输出重定向来举例,printf()默认是往屏幕上面打印数据,再调用时,底层就会找到1号文件描述符,我们只需要关闭1号文件描述符,然后用我们创建的myfile代替他,以后调用printf()函数就会找到1号文件描述符对应的内容,即往myfile中输出数据,

我们来实现一个小程序,使原来往屏幕上打印的数据,输出到文件中。

  1 #include                                                         
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 int main()
  8 {
  9 close(1);
 10 int fd=open("myfile",O_RDWR|O_CREAT,0644);
 11 if(fd<0) 
 12 {        
 13     perror("open");     
 14     return -1;          
 15 }        
 16          
 17 printf("how are you?\n");
 18 close(fd);
  }     

Linux下基础I/O_第3张图片
原本输出到屏幕上的数据就被输出到文件里面了


FILE结构和文件描述符

  1. 因为IO函数和系统调用对应,所以本质上还是操控的是文件描述符。所以再FILE结构体里面肯定封装了文件描述符。
  2. 一般的C库函数写入文件都是全缓冲的,写入显示器是行缓冲的。
  3. 而我们的系统调用接口是没有自带缓冲区的。

静态库和动态库

  1. 要了解静态库和动态库首先我们来了解一下文件系统,来看一下文件系统,每一个当我们使用ls -l 选项列出文件信息的时候,能看到文件的模式,硬链接数,文件所属者和所属组,当然还有文件大小和文件最后被修改时间,以及文件名。

  2. 但是每一个文件再计算机中如何存储的,我们来看下面这张图
    Linux下基础I/O_第4张图片
    超级快:保存着文件系统本身的结构信息。
    i节点表:存放着文件的属性,如大小,所有者,最后修改时间
    数据区:存放着文件的内容

  3. 在查找一个文件的时候,并不是利用文件名来找,而是用文件名对应的inode(其实在linux中一个inode可以对应多个inode,)

  4. 我们可以使用ln命令来使两个文件对应同一个inode。Linux下基础I/O_第5张图片
  5. 我们可以看出, 1 和 2 文件的 元信息中有 一列变成了2.
  6. 我们把通过inode引用另外一个文件叫做硬链接,把通过文件名引用另一个文件叫做软链接

静态库

程序在编译链接的过程中,把库的代码全部链接到可执行文件中,运行期间不需要静态库,这样造成可执行文件太大,并且效率低。
静态库命名规则 libXXX.a(lib是前缀,.a是后缀,XXX是库名)

生成方法

  1. 先使用gcc -c选项使目标文件在汇编完成后结束生成.o文件
  2. 使用ar -rc 库名 目标文件 来生成动态库
    . Linux下基础I/O_第6张图片

链接方法

  1. gcc man.c -L . -l mymath
    -L选项后面加上库的路径,-l选项后加上库名,注意删除掉前缀后缀
    Linux下基础I/O_第7张图片

动态库

程序在运行期间才回去链接到动态库的代码,多程序 共享使用库的代码。一个动态库链接的可执行程序仅仅包含它用到的函数的入口地址,而不是外部函数所在目标文件的整个机器码。节省了资源规则:libXXX.so
动态库命名

生成方法

gcc -shared表示生成共享库格式
gcc -fPIC表示生成位置无关的码
Linux下基础I/O_第8张图片

链接方法

gcc man.c -L . -l mymath

你可能感兴趣的:(Linux)