【Linux】基础IO(文件接口、文件描述符、重定向、库、软硬链接)

目录

C文件接口

1、fopen

2、fwrite 

3、fread

 4、fseek 

5、代码验证

系统调用文件接口

1、open

2、write  

3、read 

4、lseek

5、代码验证 

文件描述符 

值和含义:

 文件描述符和文件流指针的关系

重定向  

 1、重定向符号

 2、重定向的接口

3、内核角度理解重定向

动态库和静态库

1、什么是库

2、动态库

特征:

生成:

 使用动态库:

 3、静态库

特征:

生成:

​查看静态库: 

​ ​

使用 

软硬链接

软链接

硬链接 



C文件接口

1、fopen

 path:带有路径的文件名称,不带路径,则默认当前路径

mode:打开文件的方式

返回值:成功返回文件流指针FILE*,失败返回NULL

mode打开方式的方式:

r:只读方式打开,将文件指针指向文件头,如果文件不存在,则返回空。

r+:读写方式打开,将文件指针指向文件头,如果文件不存在,则返回空。

w:写入方式打开,将文件指针指向文件头并将文件内容清空。如果文件不存在则创建。

w+:读写方式打开,将文件指针指向文件头并将文件内容清空,如果不存在则创建。

a:写入方式打开,将文件指针指向文件末尾。如果文件不存在则创建。

a+:读写方式打开,将文件指针指向文件末尾。如果文件不存在则创建。 

2、fwrite 

 ptr:向文件中写入什么内容

size:写入多少字节

nmemb:期望写多少块(就是多少个size)

stream:文件流指针

返回值:返回成功写入的块数

3、fread

 ptr:从文件中读到的内容保存到ptr指向的空间中

size:读多少字节

nmemb:读多少块(就是多少个size)

stream:文件流指针 

返回值:返回成功读入的个数

 4、fseek 

作用:移动文件流指针的位置 

stream:文件流指针

offset:偏移量

whence:将文件流指针偏移到什么位置

                SEEK_SET:文件头部

                SEEK_CUR:文件流指针的位置

                SEEK_ENO:文件末尾

返回值:成功返回0,失败返回-1。

5、代码验证

errno:系统当中的一个错误码;当我们调用一个函数出错了,则会给errno赋值成为对应的错误码(整形)。

perror:会直接去拿errno当中的值进行解析,解析完毕后,进行打印。 

 #include<stdio.h>
  2 #include<string.h>
  3 int main(){
  4     FILE* fp = fopen("1.txt","w+");
  5     if(fp == NULL){
  6         perror("fopen");
  7         return 0;
  8     }
  9     //测试写
 10     const char* ptr = "hello world";
 11      printf("sucess\n");
 12     size_t wsize= fwrite(ptr,1,strlen(ptr),fp);
 13     printf("%ld\n",wsize);
 14      //测试读
 15      fseek(fp, 3, SEEK_SET);
 16      char buf[1024] = {0};
 17      size_t r_size = fread(buf, 1, sizeof(buf) - 1, fp);
 18      printf("r_size = %ld\n", r_size);
 19      printf("buf = %s\n", buf);
 20      //如果不关闭文件流指针,则会造成文件句柄泄露
 21     fclose(fp);
 22     return 0;
 23 }
 24              

系统调用文件接口

1、open

pathname:要打开或者创建的目标文件

flags:打开方式

①O_RDONLY:只读打开

②O_WRONLY:只写打开

③O_RDWR:读写打开

注意:这三个常量,必须指定且指定一个,用下面一个或者多个常量进行“或运算”构成flags

O_CREAT:若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限。

O_APPEND:追加写

mode:指定新创建文件的权限 

返回值:成功返回新文件的文件描述符,失败返回-1

2、write  

fd:文件描述符

buf:将buf指向的内容写入到文件中

count:期望写多少字节

返回值:返回写入的字节数量 

3、read 

 fd:文件描述符

buf:从文件中读到的内容写入buf指向的空间去。

count:期望都多少字节

返回值:返回读到的字节的数量

4、lseek

 

fd:文件描述符

offset:偏移量,单位字节

 whence:将文件流指针偏移到什么位置

                SEEK_SET:文件头部

                SEEK_CUR:当前文件流指针的位置

                SEEK_END:文件末尾

返回值:成功返回0,失败返回-1

5、代码验证 

#include<unistd.h>
#include<stdio.h>
#include<string.h>
int main(){
    int fd = open("1.txt",O_RDWR | O_CREAT,0664);
    if(fd < 0){
        perror("open");
        return 0;
    }
    printf("open sucess\n");
    //测试写
    const char* buf = "Linux is so easy";
    ssize_t fsize = write(fd,buf,strlen(buf));
    printf("fsize = %ld\n",fsize);
    //测试读
    lseek(fd,0,SEEK_SET);
    char temp[1024] = {0};
    ssize_t rd_size = read(fd,temp,sizeof(temp) - 1);
    printf("rd_size = %ld\n",rd_size);
    close(fd);
    return 0;
}

注意:这里read这里传的是sizeof(temp) - 1;在字符数组中预留了\0的位置,防止后续在访问的时候越界访问导致崩溃。 

文件描述符 

值和含义:

Linux进程默认情况下会有3个打开的文件描述符,分别是标准输入0,标准输出1,标准错误2。它们对应的物理设备一般是:键盘,显示器,显示器。

 int main(){
  6     int fd = open("1.txt",O_RDWR | O_CREAT,0664);
  7     if(fd < 0){
  8         perror("open");
  9         return 0;
 10     }
 11     printf("%d\n",fd);
 12     while(1){
 13                                                                                                                                                  
 14     }

可以看到拿到的文件描述符是3,这是一个正数。 可以通过/proc/[pid]/fd查看文件夹下的文件描述符信息。

其中的软连接文件的名字,正好对应文件描述符的值。站在操作系统内核的角度上来理解:

文件描述符就是从0开始的整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体,表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让文件和进程关联起来。每个进程都有一个指针*file,指向一张表files_struct,该表最重要的部分就是包含一个指针数组,每一个元素都是一个指向打开文件的指针!所以,本质上,文件描述方法就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。 

 文件描述符和文件流指针的关系

文件流指针指向的结构体中保存了文件描述符;文件流指针对应的结构体struct  _IO_FILE这个结构体内部的成员变量int _fileno保存了对应的文件描述符的数值。

 int main(){
  4     FILE* fp = fopen("1.txt","w+");
  5     if(fp == NULL){
  6         perror("fopen");
  7         return 0;
  8     }
  9     printf("%d\n",fp->_fileno);

 

重定向  

 1、重定向符号

>:清空重定向

>>:追加重定向

 

 2、重定向的接口

作用:将newfd的值重定向为oldfd,即newfd拷贝oldfd 

参数:oldfd/newfd均为文件描述符

成功:关闭newfd;让newfd指向oldfd对应的struct file*结构体

失败:如果oldfd是一个非法/无效的文件描述符,则重定向失败,newfd没有变化;如果oldfd和newfd的值相等,则什么事都不干。

3、内核角度理解重定向

看如下代码:

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include <sys/types.h>

int main(){
    int fd = open("myfile",O_RDWR | O_CREAT,0664);
    if(fd < 0){
        perror("open");
        return -1;
    }
    dup2(fd,1);
    printf("hello\n");
    fflush(stdout);
    while(1){

    }
}

 可以看到本该打印到屏幕的内容去到了myfile里面

现在来查看文件描述符的信息:

可以看出本该指向标准输出的指针指向了myfile文件。

文件描述符是一个file结构体里面的一个指针数组的下标,重定向就是改变了其中指针的指向。(使本该指向标准输出的指针指向了myfile文件) 

动态库和静态库

1、什么是库

静态库和动态库都是程序代码(二进制文件)的集合,一般为了方便将程序提供给第三方使用,就是将程序编写为库文件提供给第三方使用。

好处:不会泄露公司的源码;调用者不必关心内部实现,只需要关心如何使用即可。

静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。

动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

2、动态库

特征:

windows:没有前缀,后缀为dll

linux:前缀为lib,后缀为.so

生成:

使用gcc/g++编译器,增加两个命令行参数:

-fPIC: 产生位置无关码

-shared:表示生成共享库格式

库名格式:libxxx.so

  

 

 

 使用动态库:

 编译可执行程序的时候,依赖动态库:

-L  [path]:指定动态库所在的路径

-l[动态库的名称(去掉前缀和后缀之后的名称)]

 

 可以看到这里虽然编译通过,但是却没有运行成功。可以使用ldd命令查看程序依赖的库:

原因就是运行的时候找不到库文件的位置。 下面的三种方法可以让程序找到动态库:

1、将动态库放到可执行程序的路径下(不推荐)

2、在~/.bashrc文件下配置LD_ LIBRARY_PATH:动态库的环境变量(推荐)

3、放到系统库的路径下:/lib64(极力不推荐)

 

 3、静态库

特征:

windows:没有前缀,后缀为.lib

linux:前缀为lib,后缀为.a

生成:

第一阶段:使用gcc/g++将源代码编译成为目标程序(.o)

第二阶段:使用ar -rc命令编译目标程序为静态库

ar -rc [静态库文件名称] [目标程序]

注意:不能直接用源代码编译 

 

 

查看静态库: 

 

使用 

 如果在编译可执行程序时候,使用到了静态库,则静态库会被编译到可执行程序当中去。并没有可执行程序以来动态库的问题

 

软硬链接

软链接

软链接:目标文件的快捷方式

生成 :ln -s 源文件 软链接文件

注意事项:

1、修改软链接文件,源文件也会被修改

2、源文件如果被删除,软链接文件还在的,修改软链接文件,会重新建立源文件,重新建立链接关系(这种要慎重);一定在删除源文件的时候,将软链接文件也删除(以防后患) 

硬链接 

硬链接:目标文件的替身

生成:ln 源文件 硬链接文件

 

 

硬链接文件和源文件拥有相同的节点号。多个文件引用用一个节点的时候,引用计数会++;当文件删除的时候,引用计数会减减,直到引用计数减到0,才会释放inode节点。 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值