Linux征途——基础IO

在学习C语言的阶段里,学过了文件操作——(C语言文件操作)Linux里,“一切皆文件的思想” ,更是围绕着文件进行操作。下面来说说Linux下的文件操作。

目录

《一》系统调用接口

《二》相关概念

《三》文件系统

《四》动态库和静态库


  • 《一》系统调用接口

    在C语言里的fopen  fread  fwrite fclose都是C标准库的的函数——库函数
    但是Linux的IO操作的open close read write lseek  是系统调用接口。这是前面说《进程》的时候一个图。

以下接口要带上<fcntl.h>这个头文件

  • 接口1>int open(const char * pathname,int flags, mode_t mode)     返回值是文件描述符

    pathname:文件名称
    flags:参数选项/控制字:它们用 | 隔开。
    必选
    O_RDONLY        以只读方式打开文件
    O_RDWR            以可读写方式打开文件
    O_WRONLY        以只写方式打开文件
    可选
    O_APPEND        读写文件从文件尾部开始移动,所写入的数据追加到文件尾            重定向>>
    O_TRUNC          若文件存在并且以可写的方式打开时,此标志会将文件长度清为0,而原来存于该文件的资料也会消失        重定向>
    O_CREAT           若路径中的文件不存在则自动建立该文件
    O_EXCL              如果与O_CREAT同时设置,此指令会去检查文件是否存在,文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且将要打开的文件为符号连接,则将导致打开文件失败
     mode                   如果需要open创建文件,mode是给这个创建的文件一个默认权限的。

  • 接口2>ssize_t write (int fd, const void * buf, size_t count);

    fd:文件描述符
    buf:要写入的数据
    count:写入数据的长度
    返回值:实际写入的长度 失败,-1

  • 接口3>ssize_t read(int fd, void * buf, size_t count);

    返回值 实际读取的字节,失败:-1
    fd:文件描述符
    buf:要读取的数据存入的位置
    count:读取数据的长度

  • 接口4>off_t lseek(int fd, off_t offset, int whence);

    fd             表示要操作的文件描述符
    offset        是相对于whence(基准)的偏移量
    whence         可以是SEEK_SET(文件指针开始),SEEK_CUR(文件指针当前位置) ,SEEK_END为文件指针尾
    返回值:        文件读写指针距文件开头的字节大小,出错,返回-1
当我们打开一个空文件时,默认情况下文件指针指向文件流的开始。write和read函数本身自带移动文件指针的功能,当我write、read  n个字节后,文件指针会从文件流的开始自动向后移动n位。所以当我们用lseek显式的将文件指针移动后,那么再去read/write时就是从移动过后的位置开始的。


所以我们可以用这个接口来扩展文件大小、获取文件大小、用lseek构建空洞文件(空洞文件就是这个文件中有一段是空的。我们打开一个文件后,用lseek往后跳过一段,再write写入一段,就会构成一个空洞文件。)

  • 《二》相关概念

1>文件描述符
    进程对文件的管理:描述 + 组织
    描述:数组的下标
    组织:结构体数组;描述符就是结构体数组的下标,通过下标找到文件描述信息,进行对文件的操作
    分配规则:遵循最小未使用的下标。
2>文件流流指针 FILE*
    文件流指针与文件描述符的关系
        文件流指针这个结构体中封装了文件描述符作为成员变量
        文件流指针包含了缓冲区。普通文件不具备刷新缓冲区的功能,只有标准输出文件才有这个功能

3>文件重定向
    改变描述符下标所对应的文件描述信息
   函数:
    int dup2(int oldfd, int newfd);
    成功返回新的文件描述符,失败则返回-1
   newfd来指定新描述符数值,若newfd指向的文件已经被打开,会先将其关闭。若newfd等于oldfd,就不关闭newfd,newfd和oldfd共同指向一份文件



 
提一下dup(oldfd):这个等于创建一个文件描述符也指向这个文件

  操作符:
    >    清空文件原有的内容,将新数据写入    
    >>    将新数据追加写入到文件中

   对之前编写的自主shell进行修改,使其支持输入/输出/追加重定向

//C语言
  1 //1.获取标准输入
  2 //2.对输入字符串进行解析(获取程序名称 + 参数)
  3 //3.创建子进程
  4 //  程序替换
  5 //4.进程等待
  6 
  7 #include<stdio.h>
  8 #include<unistd.h>
  9 #include<stdlib.h>
 10 #include<fcntl.h>
 11 #include<string.h>
 12 char buff[1024] = {0};//输入缓冲
 13 char* argv[1024];
 14 int argc = 0;
 15 void menu(char* buff)//输入菜单
 16 {
 17     printf("[top-down@localhost]$");
 18     fflush(stdout);
 19     //判断进行回车判定,防止第一个字符就是回车
 20     if(scanf("%[^\n]*c",buff) != 1)//^\n正则表达式,遇到\n截至,*c(s)表示抛弃剩下的字符(字符串)
 21     {
 22         getchar();
 23     }
 24     printf("%s\n",buff);
 25 }
 26 void explain(char* buff)//对输入字符串进行解析
 27 {
 28     char* ptr = buff;
 29     while(*ptr != '\0')//不到结尾,一直循环
 30     {
 31         //当前位置非空白字符
 32         if(!isspace(*ptr))//isspace() 检测空白字符,制表符、换行、回车、空格等
 33         {
 34             argv[argc++] = ptr;//保存字符串地址
 35             while(!isspace(*ptr) && *ptr != '\0')
 36             {
 37                 ++ptr;
 38             }
 39         }
 40         else
 41         {
 42             *ptr = '\0';
 43             ++ptr;
 44         }
 45     }
 46     argv[argc] = NULL;
 47     int i;
 48     for(i = 0; i < argc; ++i)
 49     {
 50         printf("[%s]",argv[i]);
 51     }
 52     printf("\n");
 53 }
 54 void create()
 55 {
 56     pid_t pid = fork();
 57     if(pid < 0)
 58     {
 59         exit(-1);
 60     }
 61     else if(pid == 0)
 62     {
 63         int i = 0;
 64         int flag = 0;
 65         char* str = ">>";
 66         for(i = 0; argv[i] != NULL; ++i)
 67         {
 68             if(strcmp(str,argv[i]) == 0)
 69             {
 70                 flag = 1;
 71                 break;
 72             }
 73         }
 74         argv[i] = NULL;
 75         int newfd;
 76         if(flag == 1)
 77         {
 78             if(argv[i+1] == NULL)
 79             {
 80                 printf("ERROR!\n");
 81                 exit(-1);
 82             }
 83             else
 84             {
 85                 newfd = open(argv[i+1],O_RDWR|O_CREAT,0664);
 86                 dup2(newfd,1);
 87             }
 88         }
 89         execvp(argv[0], argv);
 90         close(newfd);
 91         //防止程序替换失败,直接退出
 92         exit(0);
 93     }
 94     wait(NULL);
 95 }
 96 int main()
 97 {
 98     menu(buff);
 99     explain(buff);
100     create();
101     return 0;
102 }
  • 《三》文件系统

    a、五大部分:超级块,inode结点位图,数据位图,inode,data
    普通文件和目录:目录也是文件,数据存储的是目录项(文件名和inode节点号)

    例如:    cat file:通过文件名在目录项中获取文件inode结点,通过inode结点再到存储位置,读取文件
    b、软连接和硬链接:ln
        软链接:类似快捷方式,存储的是文件的路径。软连接文件和源文件不是同一个文件,有不同的inode号
        硬链接:类似引用,文件的别名。硬链接文件具有相同的inode结点号

        根据上图更容易理解以下的特性:
                   删除源文件,软连接失效,但是硬链接不影响,只是连接数-1(当一个连接数为0的时候才是真正删除一个文件,否则只是删除目录项)
                    软连接可以针对目录创建,硬链接不可以
                   软连接可以跨分区创建,硬链接不可以
      c、 相关命令:
        fd:查看分区挂载情况
        du:文件占磁盘空间大小

  • 《四》动态库和静态库

    动态链接:生成链接
    静态链接:直接拷贝代码

    I、库 :保存实现函数代码的文件
    II、生成库:需要将所有目标文件集合到一起,生成一个打包后的代码库

    III、 生成动态库:
                    gcc -fPIC -c b.c -o b.o            fPIC:产生位置无关代码
                    gcc --share -o xxx.so            share:生成共享库
        动态库命名:以lib为前缀,以.so为后缀,中间是库名称
    IV、生成静态库:
                    ar(静态库链接器)                cr(create创建 raplace模块替换)
                    ar -cr xxx.a b.o
        静态库命名:以lib为前缀,以 .a 为后缀,中间是库名称

    V、静态库/动态库的链接:
    gcc -o -a -lmy_b
    生成可执行程序时,系统需要的所有库都在指定路径(/lib64)下,系统根据名称进行寻找。
    如果不想自己的库将库放在/lib64,可以指定库查找路径(只针对静态库)。链接的时候,优先是动态库,所以在/lib64目录下不能有相同名称的动态库。
    -L 指定路径
    -l 指定链接的库名称
    动态链接生成的可执行程序,需要动态库的存在,并且存在于指定路劲下,因此最好直接拷贝到/lib84

例如:实现一个动态库
我们先创建我们的函数:

接下来我们需要把写的文件封装成动态库

动态库只能在默认的lib64下,所以我们复制下

接下来我们写一个test.c

现在我们进行链接

a 和 b都是整型的。所以商是 0 。

 ldd 查看链接库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值