第一章:Linux系统编程入门

第一章

1 动态库静态库

制作并使用静态库

库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用 者一些可以直接拿来用的变量、函数或类。

库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。

库文件有两种,静态库和动态库(共享库),区别是:静态库在程序的链接阶段被复制到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。

库的好处:1.代码保密 2.方便部署和分发

在这里插入图片描述

实验:
制作静态库

image-20230710163238561

[wt@study lesson03]$ cd calc/
[wt@study calc]$ ls #查看当前文件夹下的文件
add.c  div.c  head.h  main.c  mult.c  sub.c
[wt@study calc]$ gcc -c add.c div.c mult.c sub.c #生成目标文件
[wt@study calc]$ ls 
add.c  add.o  div.c  div.o  head.h  main.c  mult.c  mult.o  sub.c  sub.o
[wt@study calc]$ ar rcs libcalc.a add.o sub.o mult.o div.o #打包生成静态库
[wt@study calc]$ ls #查看是否生成成功
add.c  add.o  div.c  div.o  head.h  libcalc.a  main.c  mult.c  mult.o  sub.c  sub.o
[wt@study calc]$ 
使用静态库

现在制作了一个包含add.o sub.o div.o mult.o 的一个库,可以提供给别人使用但是,别人不知道你这个库中有哪些函数可以使用,所以需要相应的.h头文件来说明库里面有哪些函数。

include/:文件夹下放头文件

lib/:放库文件

[wt@study newcode]$ cd lesson03 #进入lesson03文件夹下
[wt@study lesson03]$ cd calc/
[wt@study calc]$ cp libcalc.a ../library/lib/ #将刚刚生成的libcalc.a库,复制到lesson03/library/lib文件夹下(再library文件夹下做实验)
[wt@study calc]$ cd ..
[wt@study lesson03]$ cd library/
[wt@study library]$ gcc main.c -o main -I ./include/ -l calc -L ./lib/
[wt@study library]$ gcc main.c -o main -I ./include/ -l calc -L ./lib/
[wt@study library]$ ./main 
a = 20, b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.666667

制作并使用动态库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5vokZRgF-1690294444037)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230710171737425.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H76hyGsg-1690294444037)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230710171751730.png)]

实验:
制作动态库
[wt@study newcode]$ mkdir lesson06
[wt@study newcode]$ ls
lesson02  lesson03  lesson04  lesson06
[wt@study newcode]$ cp -r ./lesson04/calc/ ./lesson04/library/ lesson06
[wt@study newcode]$ cd lesson06
[wt@study library]$ cd lib/
[wt@study lib]$ rm libcalc.a #删除之前创建的静态库
[wt@study lib]$ cd ..
[wt@study library]$ cd ..
[wt@study lesson06]$ cd calc/
[wt@study calc]$ rm *.o#删除之前生成的目标文件
[wt@study calc]$ rm libcalc.a
[wt@study calc]$ ls
add.c  div.c  head.h  main.c  mult.c  sub.c#删除完成
[wt@study calc]$ gcc -c -fpic add.c div.c mult.c sub.c #生成制作动态库的目标文件
[wt@study calc]$ ls
add.c  add.o  div.c  div.o  head.h  main.c  mult.c  mult.o  sub.c  sub.o
[wt@study calc]$ gcc -shared *.o -o libcalc.so #制作动态库
[wt@study calc]$ ls
add.c  add.o  div.c  div.o  head.h  libcalc.so  main.c  mult.c  mult.o  sub.c  sub.o
使用动态库

将刚才生成的动态库放在library/lib/文件夹下,

[wt@study calc]$ cd ..
[wt@study lesson06]$ cp -r ./calc/libcalc.so ./library/lib/
[wt@study lesson06]$ cd library/
[wt@study library]$ gcc main.c -o main -I ./include/ -L lib/ -l lib/libcalc.so#-L指定在哪个文件夹下搜索,-l制定要加载的库的名字
[wt@study library]$ ./main 
./main: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory
配置动态库

报错:提示找不到动态库文件,查看其依赖

[wt@study library]$ ldd main
        linux-vdso.so.1 =>  (0x00007ffc44f4f000)
        libcalc.so => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007fe90efd3000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe90f3a1000)

配置环境变量:将动态库的绝对路径添加到环境变量中。看上图会在LD_LIBRARY_PATH中查找,所以将我们的动态库的绝对路径加入到环境变量LD_LIBRARY_PATH中,这样动态链接器就会加载我们的动态链接库

1但下面这种方法只能在一个终端内有效,退出再重新就不行了

[wt@study lib]$  export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/wt/newcode/lesson06/library/lib
[wt@study lib]$ echo $LD_LIBRARY_PATH #输出环境变量。查看是否成功
:/home/wt/newcode/lesson06/library/lib
[wt@study lib]$ cd ..
[wt@study library]$ ldd main#查看依赖,发现已经可以了
        linux-vdso.so.1 =>  (0x00007ffee075c000)
        libcalc.so => /home/wt/newcode/lesson06/library/lib/libcalc.so (0x00007f196e104000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f196dd36000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f196e306000)

2永久配置:

用户级别配置:

在用户家目录下有个隐藏文件 .bashrc,可以在里面配置环境变量。

[wt@study wt]$ ls -a
.   .bash_history  .bash_profile  .cache   .dbus    .esd_auth      .kde       .local    newcode  text1        .viminfo        .Xauthority  模板  图片  下载  桌面
..  .bash_logout   .bashrc        .config  .dotnet  .ICEauthority  lession02  .mozilla  .ssh     text.ta
r.xz  .vscode-server  公共         视频  文档  音乐
[wt@study wt]$ vim .bashrc
[wt@study ~]$ source .bashrc

添加

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2mTqqi5E-1690294444037)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230710214127527.png)]

再从新开一个终端

[wt@study ~]$ cd newcode/lesson06/library/
[wt@study library]$ ls
include  lib  main  main.c  src
[wt@study library]$ ldd main
	linux-vdso.so.1 =>  (0x00007ffecd39d000)
	libcalc.so => /home/wt/newcode/lesson06/library/lib/libcalc.so (0x00007f8773781000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f87733b3000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f8773983000)
[wt@study library]$ ./main 
a = 20, b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.6

系统级别配置:

[wt@study ~]$ sudo vim /etc/profile
[wt@study ~]$ source /etc/profile

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c5VFvyho-1690294444038)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230710214935071.png)]

3 修改ld.so.cache

[wt@study library]$sudo vim /etc/ld.so.conf
[wt@study library]$ sudo ldconfig

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7QFfepAg-1690294444038)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230710215619180.png)]

4.将动态库放在 /lib,/usr/lib下,但不推荐

总结:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HrVbRl9o-1690294444038)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230710220807659.png)]
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2 Makefile

在这里插入图片描述
在这里插入图片描述

version1:

[wt@study lesson07]$ vim Makefile
[wt@study lesson07]$ make
gcc  main.c add.c sub.c div.c mult.c -o app

在这里插入图片描述

version2:
在这里插入图片描述

多规则:规则是为第一条规则服务

[wt@study lesson07]$ vim Makefile#编写新的makefile文件
[wt@study lesson07]$ rm app#删除原来的
[wt@study lesson07]$ ls
1.10 Makefile.pptx.pdf  add.c  div.c  head.h  main.c  Makefile  mult.c  redis-5.0.10  redis-5.0.10.tar.gz  sub.c
[wt@study lesson07]$ make#执行makefile
gcc -c main.c -o main.o
gcc -c sub.c -o sub.o
gcc -c div.c -o div.o 
gcc -c mult.c -o mult.o
gcc -c add.c -o add.o
gcc  main.o add.o sub.o div.o mult.o -o app

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SBinPOf8-1690294444041)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711104355736.png)]

version3:

使用变量

在这里插入图片描述
在这里插入图片描述

[wt@study lesson07]$ rm app
[wt@study lesson07]$ vim Makefile
[wt@study lesson07]$ make
gcc -c main.c -o main.o
gcc -c sub.c -o sub.o
gcc -c div.c -o div.o
gcc -c mult.c -o mult.o
gcc -c add.c -o add.o
gcc  main.o sub.o div.o mult.o add.o -o app

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6jl3wgT3-1690294444042)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711105950376.png)]

version4:

使用函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ry4xLBi9-1690294444042)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711110117706.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dev3TxLj-1690294444043)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711110133879.png)]

[wt@study lesson07]$ rm app
[wt@study lesson07]$ vim Makefile
[wt@study lesson07]$ make
gcc -c mult.c -o mult.o
gcc -c main.c -o main.o
gcc -c add.c -o add.o
gcc -c div.c -o div.o
gcc -c sub.c -o sub.o
gcc  ./mult.o ./main.o ./add.o ./div.o ./sub.o -o app

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FxPpdiQI-1690294444043)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711112826443.png)]

执行完后生成可执行文件app而.o文件可以删除:

[wt@study lesson07]$ vim Makefile
[wt@study lesson07]$ make clean
rm ./mult.o ./main.o ./add.o ./div.o ./sub.o -f

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BPQeRKwN-1690294444043)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711113248874.png)]

若当前文件夹下有clean文件,则不会执行,可以添加.PAONY:clean表明clean是伪目标,不会生成clean文件,则就不会根clean对比了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D2Z3BlXv-1690294444043)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711113502634.png)]

3.GDB调试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpEIExbw-1690294444044)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711113812154.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kgj32gYz-1690294444044)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711114207597.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3VuIMdgk-1690294444044)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711114936156.png)]

list或者l命令,不是list/l命令,

show list/listsize 显示的是默认list会显示多少行代码

可以通过设置 list或者listsize来改变list/l显示的代码行数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Ss8V5h2-1690294444044)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711121907133.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q6xoBNK3-1690294444045)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230711121924238.png)]

4.文件IO

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O3L8Kadj-1690294444045)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230712111056034.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cm0177IY-1690294444045)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230712113613375.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vSJzGX7a-1690294444045)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230712115341156.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vDII8RI-1690294444046)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230712124740131.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BJ870wjO-1690294444046)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230712202001625.png)]

open() clost() 函数

标准c库的函数是跨平台的,因为它会调用操作系统提供的的API

文件描述符表是一个长度为1024的一个数组,里面存放的是文件描述符(索引到磁盘文件),每打开一个文件就占用一个,其是由操作系统内核来维护,前三个默认指向的是当前终端的:标准输入,标准输出,标准错误。

同一个程序打开同一个文件也会创建不同的文件描述符。

linux系统API:

#includ e <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//1打开一个已经存在的文件
int open(const char *pathname, int flags);
//参数:
   // -pathname:要打开的文件路径
   // -flags:对所要打开文件的操作权限, 有:O_RDONLY, O_WRONLY 或 O_RDWR ,O_APPEND(指明 文件 是以 只读 , 只写 或 读写方式,追加模式 打开的)
   // -返回值:返回一个新的文件描述符
	//errno:属于linux操作系统函数库,是库里面的一个全局变量,记录最近的错误信息。
//c标准库中:
        #include <stdio.h>
   		void perror(const char *s);
//这个函数的作用就是打印errno的信息,s是用户描述。类似用户名。

//2打开一个新的文件
int open(const char *pathname, int flags, mode_t mode)
//参数:
//-pathname:要打开或创建的文件的路径
//-flags:对文件的操作权限和其他设置,必选项有:O_RDONLY, O_WRONLY 或 O_RDWR (指明 文件 是以 只读 , 只写 或 读写 方式 打开的),可选项:O_CREAT文件不存在则创建
//-mode:八进制数,表示创建出来的文件的权限。文件的最终权限是mode&~umask。umask是用户默认权限,与上~umask的作用是权限不得超过用户默认的权限。
    

open(a1,a2)实验:使用open()打开一个文件


[wt@study lesson09]$ vim main.c 
[wt@study lesson09]$ gcc main.c
[wt@study lesson09]$ ls
a.out  main.c
[wt@study lesson09]$ ./a.out 
open: No such file or directory

main.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include  <unistd.h>
int main(){
        int fd=open("a.txt",O_RDONLY);
        if(fd==-1){
                perror("open");
        }
        close(fd);
        return 0;
}

open(a1,a2,a3)实验:

实验:使用open()创建一个文件

[wt@study lesson09]$ gcc main.c -o new_main
[wt@study lesson09]$ ls
a.out  main  main.c  new_main
[wt@study lesson09]$ ./new_main 
[wt@study lesson09]$ ll
总用量 40
-rwxrwxr-x. 1 wt wt 8496 712 19:55 a.out
-r----x--t. 1 wt wt    0 712 20:14 a.txt
-rwxrwxr-x. 1 wt wt 8496 712 19:58 main
-rw-rw-r--. 1 wt wt  539 712 20:14 main.c
-rwxrwxr-x. 1 wt wt 8496 712 20:14 new_main

执行完后当前文件夹下创建了a.txt文件。

int fd=open("a.txt",O_RDONLY|O_CREAT,777);
        if(fd==-1){
                perror("open:");
        }
        close(fd);
        return 0;

read() write()函数

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
//描述
       //read() 从文件描述符 fd(open得到的) 中读取 count 字节的数据并放入从 buf 开始的缓冲区中.
       //如果 count 为零,read()返回0,不执行其他任何操作.  如果 count 大于SSIZE_MAX,那么结果将不可预料.
//返回值:
	//>0:返回实际读取的字节数
    //=0:文件读完
    //=-1:失败,并且全局变量errno已被设置相应的错误
    //成功时返回读取到的字节数(为零表示读到文件描述符), 此返回值受文件剩余字节数限制.当返回值小于指定的字节数时并不意味着错误;这可能是因为当前可读取的字节数小于指定的字节数(比如已经接近文件结尾,或者正在从管道或者终端读取数 据,或者 read()被信号中断).  发生错误时返回-1,并置 errno 为相应值.在这种情况下无法得知文件偏移位置是否有变化.
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
//描述
       //write  向文件描述符  fd  所引用的文件中写入从 buf 开始的缓冲区中 count 字节的数据.  POSIX规定,当使用了write()之后再使用 read(),那么读取到的应该是更新后的数据.  但请注意并不是所有的文件系统都是POSIX兼容的.
//返回值
	//>0:返回实际写入的字节数
    //=0:没有写入
    //-1:失败,并且全局变量errno已被设置相应的错误
       //成功时返回所写入的字节数(若为零则表示没有写入数据).  错误时返回-1,并置errno为相应值.  若count为零,对于普通文件无任何影响,但对特殊文件 将产生不可预料的后果.

实验:将english.txt的内容复制到copy.txt需要自己创建中。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(){
    //创建文件
    int obfd=open("copy.txt",O_WRONLY|O_CREAT,0664);
    if(obfd==-1){
        perror("creat");
        return -1;
    }
    //打开文件
    int srcfd=open("english.txt",O_RDONLY);
    if(srcfd==-1){
        perror("open");
        return -1;
    }

    char chs[1024]={0};
    //chs[1024]='\0';
    int len;
    while((len=read(srcfd,chs,sizeof(chs)))>0){
        write(obfd,chs,len);
    }
    close(obfd);
    close(srcfd);
}

lseek()

//linux系统API
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//参数:
	//-fd:文件描述符,通过open获得
    //-offset:偏移量
    //-whence:SEEk_SET:设置文件指针的偏移量
	//		SEEK_CUR:设置偏移量:当前位置+第二个参数offset的值
	//		SEEK_END:设置偏移量:文件大小+第二个参数offset的值
//作用:
	//1.移动文件指针到头文件:lseek(fd,0,SEEK_SET)
	//2.获取当前文件指针的位置:lseek(fd,0,SEEK_CUR);返回当前位置
	//3.获取当前文件的长度: lseek(fd,0,SEEK_END);返回文件长度
	//4.拓展文件的长度:lseek(fd,100,SEEK_END);文件增加了100个字节,记得再执行完这句后,在扩展的指针那里写个空数据,不然不会拓展
//c标准库的API:
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
//看参数就能看出来,lseek接受有linux系统API:open()返回的文件描述符,而fseek接受有fopen()返回的FILE*指针

实验:扩展文件长度

创建一个1.txt文件,随便写几个字符

[wt@study lesson11]$ ll
总用量 20
-rw-rw-r--. 1 wt wt    6 712 22:19 1.txt
[wt@study lesson11]$ vim main.c
[wt@study lesson11]$ gcc main.c -o main
[wt@study lesson11]$ ./main 
[wt@study lesson11]$ ll
总用量 20
-rw-rw-r--. 1 wt wt  206 712 22:27 1.txt
-rwxrwxr-x. 1 wt wt 8600 712 22:27 main
-rw-rw-r--. 1 wt wt  374 712 22:24 main.c

增加200字节

main.c代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(){
    //读取文件
    int  fd=open("1.txt",O_RDWR);
    if(fd==-1){
        perror("open");
        return -1;
    }
    //扩展文件
    int len=lseek(fd,200,SEEK_END);
    if(len==-1){
        perror("lseek");
        return -1;
    }
    //在文件末尾写一个字符占位置
    char buf[1]="1";
    len=write(fd,buf,1);
    if(len==-1){
        perror("write");
        return -1;
    }
    close(fd);
}

stat()函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8np8YOCh-1690294444046)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713153241727.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HMsLHjHN-1690294444047)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713154039085.png)]

可以通过与S_IFMT相与获取其文件类型的位。然后通过对比相应的文件的宏就可知道是什么类型。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
//作用:获取一个文件相关的信息
/*
	参数:-pathname:操作的文件的路径
		 -stabuf:结构体变量,用于保存获取到的文件的信息
	返回值:0:成功
		   1:失败,设置errno
*/
int fstat(int fd, struct stat *buf);

实验:实现一个类似ls -l命令的程序

 #include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>
// 模拟实现ls -l功能
int main(int argc,char * argv[]){
    //判断输入是否合法
    if(argc<2){
        printf("%s filename\n",argv[0]);
        return -1;
    }else{
        //通过stat获取文件信息
            struct stat st;
            int res=stat(argv[0],&st);
            if(res==-1){
                perror("sta");
                return -1;
            }
            //获取文件类型和权限
            char perms[11]={0};
            switch (st.st_mode&&__S_IFMT)
            {
            case __S_IFSOCK:
                perms[0]='s';
                break;
            case __S_IFLNK:
                perms[0]='l';
                break;
            case __S_IFREG:
                perms[0]='-';
                break;
            case __S_IFDIR:
                perms[0]='d';
                break;
            case __S_IFCHR:
                perms[0]='c';
                break;
            case __S_IFIFO:
                perms[0]='f';
                break;
            default:
                perms[0]='?';
                break;
            }
            //判断所有者权限
            perms[1]=(st.st_mode&S_IRUSR)?'r':'-';
            perms[2]=(st.st_mode&S_IWUSR)?'w':'-';
            perms[3]=(st.st_mode&S_IXUSR)?'x':'-';
            //文件所在组权限
            perms[4]=(st.st_mode&S_IRGRP)?'r':'-';
            perms[5]=(st.st_mode&S_IWGRP)?'w':'-';
            perms[6]=(st.st_mode&S_IXGRP)?'x':'-';
            //文件其他人权限
            perms[7]=(st.st_mode&S_IROTH)?'r':'-';
            perms[8]=(st.st_mode&S_IWOTH)?'w':'-';
            perms[9]=(st.st_mode&S_IXOTH)?'x':'-';
            //硬链接数
            int linknum=st.st_nlink;
            //文件所有者
            char* filename=getpwuid(st.st_uid)->pw_name;
            char* filepasswd=getpwuid(st.st_uid)->pw_passwd;
            //文件所在组
            char* filegroupname=getgrgid(st.st_gid)->gr_name;
            //文件大小
            long int filesize=st.st_size;
            // 文件修改时间
            char* filetime=ctime(&st.st_atime);
            char time[512];
            strncpy(time,filetime,strlen(filetime)-1);
            // 打印
            char buf[1024];
            sprintf(buf,"%s %d %s %s %d %s %s",perms,linknum,filename,filegroupname,filesize,time,argv[1]);
            printf("%s\n",buf);
    }
    return 0;
}

文件属性操作函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o9vXgnI8-1690294444047)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713170519682.png)]

access()函数
#include <unistd.h>
int access(const char *pathname, int mode);
/*
作用:判断某个文件是否有某个权限,或者判断文件是否存在
        参数:
            - pathname: 判断的文件路径
            - mode:
                R_OK: 判断是否有读权限
                W_OK: 判断是否有写权限
                X_OK: 判断是否有执行权限
                F_OK: 判断文件是否存在
        返回值:成功返回0, 失败返回-1
*/

实验:判断一个文件是否存在

[wt@study lesson13]$ gcc access.c -o access
[wt@study lesson13]$ ./access 
a.txt: No such file or directory
#include <unistd.h>
#include <stdio.h>
int main(){
    if(access("a.txt",F_OK)==0){
        printf("存在");
        return 0;
    }
    printf("文件不存在");
    perror("a.txt");
    return -1;
}
chmod()函数
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
/*
   
修改文件的权限
 参数:
       - pathname: 需要修改的文件的路径
       - mode:需要修改的权限值,八进制的数
返回值:成功返回0,失败返回-1

*/

实验:改变文件的权限

[wt@study lesson13]$ ls -l
总用量 16
-rwxrwxr-x. 1 wt wt 8504 713 17:03 access
-rw-rw-r--. 1 wt wt  202 713 17:03 access.c
[wt@study lesson13]$ touch a.txt
[wt@study lesson13]$ ls -l
总用量 16
-rwxrwxr-x. 1 wt wt 8504 713 17:03 access
-rw-rw-r--. 1 wt wt  202 713 17:03 access.c
-rw-rw-r--. 1 wt wt    0 713 17:10 a.txt
[wt@study lesson13]$ touch chmod.c
[wt@study lesson13]$ gcc chmod.c -o chmod
[wt@study lesson13]$ ./chmod 
[wt@study lesson13]$ ls -l
总用量 32
-rwxrwxr-x. 1 wt wt 8504 713 17:03 access
-rw-rw-r--. 1 wt wt  202 713 17:03 access.c
-rwxrwxr-x. 1 wt wt    0 713 17:10 a.txt
-rwxrwxr-x. 1 wt wt 8448 713 17:11 chmod
-rw-rw-r--. 1 wt wt  152 713 17:11 chmod.c
#include <sys/stat.h>
#include <stdio.h>
int main() {

    int ret = chmod("a.txt", 0775);

    if(ret == -1) {
        perror("chmod");
        return -1;
    }

    return 0;
}
chown()函数
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
/*
修改文件的所有者
 参数:
       - path: 需要修改的文件的路径
       - owner:将文件所有者修改为owner
       - group:owner所在组
       /etc/password查看所有用户的用户id和组id
       /etc/password查看组id
返回值:成功返回0,失败返回-1
*/
truncate()函数
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
 /*
        作用:缩减或者扩展文件的尺寸至指定的大小
        参数:
            - path: 需要修改的文件的路径
            - length: 需要最终文件变成的大小
        返回值:
            成功返回0, 失败返回-1
*/

实验:改变一个文件的大小

[wt@study lesson13]$ ls -l
总用量 36
-rwxrwxr-x. 1 wt wt 8504 713 17:03 access
-rw-rw-r--. 1 wt wt  202 713 17:03 access.c
-rwxrwxr-x. 1 wt wt  186 713 17:19 a.txt
-rwxrwxr-x. 1 wt wt 8448 713 17:11 chmod
-rw-rw-r--. 1 wt wt  152 713 17:11 chmod.c
[wt@study lesson13]$ gcc truncate.c -o trcuncate
[wt@study lesson13]$ ./trcuncate 
[wt@study lesson13]$ ls -l
总用量 52
-rwxrwxr-x. 1 wt wt 8504 713 17:03 access
-rw-rw-r--. 1 wt wt  202 713 17:03 access.c
-rwxrwxr-x. 1 wt wt   10 713 17:33 a.txt
-rwxrwxr-x. 1 wt wt 8448 713 17:11 chmod
-rw-rw-r--. 1 wt wt  152 713 17:11 chmod.c
-rwxrwxr-x. 1 wt wt 8456 713 17:33 trcuncate
-rw-rw-r--. 1 wt wt  164 713 17:33 truncate.c
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main(){
    if(truncate("a.txt",10)==-1){
        perror("a.txt");
        return -1;
    }
}
//若是扩展的。则会用空字符填

目录操作函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4iGJfZZH-1690294444047)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713173718185.png)]

#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
 /*
        作用:创建一个目录
        参数:
            pathname: 创建的目录的路径
            mode: 权限,八进制的数
        返回值:
            成功返回0, 失败返回-1
*/
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
/*
        作用:改变目录名称
        返回值:
            0:成功
            -1:失败
*/
#include <unistd.h>
int rmdir(const char *pathname);
/*
        作用:删除目录
        返回值:
            0:成功
            -1:失败
*/
#include <unistd.h>
int chdir(const char *path);
/*
        作用:修改进程的工作目录
            比如在/home/nowcoder 启动了一个可执行程序a.out, 进程的工作目录 /home/nowcoder
        参数:
            path : 需要修改的工作目录
*/
#include <unistd.h>
char *getcwd(char *buf, size_t size);
/*
        作用:获取当前工作目录
        参数:
            - buf : 存储的路径,指向的是一个数组(传出参数)
            - size: 数组的大小
        返回值:
            返回的指向的一块内存,这个数据就是第一个参数
*/

目录遍历函数

 // 打开一个目录
    #include <sys/types.h>
    #include <dirent.h>
    DIR *opendir(const char *name);
/*
        参数:
            - name: 需要打开的目录的名称
        返回值:
            DIR * 类型,理解为目录流
            错误返回NULL
*/

    // 读取目录中的数据
    #include <dirent.h>
    struct dirent *readdir(DIR *dirp);
/*
        - 参数:dirp是opendir返回的结果
        - 返回值:
            struct dirent,代表读取到的文件的信息
            读取到了末尾或者失败了,返回NULL
*/
    // 关闭目录
    #include <sys/types.h>
    #include <dirent.h>
    int closedir(DIR *dirp);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Cccip6V-1690294444047)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713173738834.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v8Z5YfQa-1690294444048)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713181444997.png)]

实验:统计目录下有多少个普通文件

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int getFileNUM(const char* path,int deep);
void printtab1(int deep);
int main(int argc,char* argv[]){
    if(argc<2){
        printf("%s path\n",argv[0]);
        return -1;
    }
    printf("%s:\n",argv[1]);
    int num=getFileNUM(argv[1],1);
    printf("%s目录下有%d个普通文件",argv[1],num);
    return 0;
}
int getFileNUM(const char* path,int deep){
    //记录普通文件个数
    int count=0;
    //打开目录
    DIR* dir=opendir(path);
    if(dir==NULL){
        perror("opendir");
        exit(-1);
    }
    struct dirent * ptr;
    //递归读取目录内容
    while((ptr=readdir(dir))!=NULL){
        //无论是目录还是文件,先获取名称
        char* name=ptr->d_name;
        //忽略掉. 和 ..开头的文件
        if(strcmp(name,".")==0||strcmp(name,"..")==0){
            continue;
        }
        //获取文件类型,看文件是目录还是普通文件
        unsigned char type=ptr->d_type;
        //普通文件
        if(type==DT_REG){
            printf("%s\n",name);
            count++;
        }
        //目录
        if(type==DT_DIR){
            //递归读取目录
            printf("%s\n",name);
            char newname[256];
            sprintf(newname,"%s/%s",path,name);
            count+=getFileNUM(newname,deep+1);
        }
    }
    closedir(dir);
    return count;
}

dup()和dup2()函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gCWJFk4N-1690294444048)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713204010356.png)]

#include <unistd.h>
int dup(int oldfd);
/*
        作用:复制一个新的文件描述符
        fd=3, int fd1 = dup(fd),
        fd指向的是a.txt, fd1也是指向a.txt
        从空闲的文件描述符表中找一个最小的,作为新的拷贝的文件描述符
*/
#include <unistd.h>
int dup2(int oldfd, int newfd);
/*
        作用:重定向文件描述符
        oldfd 指向 a.txt, newfd 指向 b.txt
        调用函数成功后:newfd 和 b.txt 做close, newfd 指向了 a.txt
        oldfd 必须是一个有效的文件描述符
        oldfd和newfd值相同,相当于什么都没有做
*/

实验:1)复制一个文件描述符,也就是让两个不同的文件描述符指向同一个文件

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main() {
    //获取a.txt的文件描述符
    int fd = open("a.txt", O_RDWR | O_CREAT, 0664);
    //复制文件描述符,现在fd1和 fd都指向a.txt
    int fd1 = dup(fd);
    if(fd1 == -1) {
        perror("dup");
        return -1;
    }
    printf("fd : %d , fd1 : %d\n", fd, fd1);
    //关闭fd,依旧可以通过fd2来操作a.txt
    close(fd);
    //向fd2指向的文件也就是a.txt
    char * str = "hello,world";
    int ret = write(fd1, str, strlen(str));
    if(ret == -1) {
        perror("write");
        return -1;
    }
    close(fd1);
    return 0;
}

2)重定向文件描述符

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main(){
    //获取a.txt文件描述符
     int fd1 = open("a.txt", O_RDWR | O_CREAT, 0664);
     if(fd1==-1){
        perror("open");
        return -1;
     }
    //获取文件描述符
    int fd2=open("b.txt", O_RDWR | O_CREAT, 0664);
    if(fd2==-1){
        perror("open");
        return -1;
     }
    printf("fd1 : %d , fd2 : %d\n", fd1, fd2);
    //重定向前使用fd2向文件写入“ni”,实际会向b.txt文件写入
     char* cs1="ni";
     int res1=write(fd2,cs1,strlen(cs1));
     if(res1==-1){
        perror("write");
        return -1;
     }
    //重定向,将fd2重定向到fd1所指向的文件
    dup2(fd1,fd2);
    //现在通过fd2再写入就是向a.txt文件写入
    char* cs2="hao";
    int res2=write(fd2,cs2,strlen(cs2));
     if(res2==-1){
        perror("write");
        return -1;
     }
     printf("fd1 : %d , fd2 : %d\n", fd1, fd2);
     close(fd2);
     close(fd1);
}

fcntl()函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UTnb46Fi-1690294444048)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230713211012643.png)]

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ...);
/*
    参数:
        fd : 表示需要操作的文件描述符
        cmd: 表示对文件描述符进行如何操作
            - F_DUPFD : 复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)
                int ret = fcntl(fd, F_DUPFD);
            - F_GETFL : 获取指定的文件描述符文件状态flag
              获取的flag和我们通过open函数传递的flag是一个东西。
            - F_SETFL : 设置文件描述符文件状态flag
              必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
              可选性:O_APPEND, O)NONBLOCK
                O_APPEND 表示追加数据
                NONBLOK 设置成非阻塞
        阻塞和非阻塞:描述的是函数调用的行为。
*/

实验:获取文件状态,并且将覆盖模式改为追加模式

原来:a.txt:11111111111

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include <string.h>
int main(){
    int fd=open("a.txt",O_WRONLY,0762);
    if(fd==-1){
        perror("open");
        return -1;
    }
    int flag=fcntl(fd,F_GETFL);
    if(flag==-1){
        perror("fcntl");
        return -1;
    }
    printf("文件状态:%d\n",flag);
    //写入,覆盖模式
    char * c1="2";
    int res=write(fd,c1,strlen(c1));
    if(res==-1){
        perror("write");
        return -1;
    }
    //修改文件状态为追加模式
    flag|=O_APPEND;
    res=fcntl(fd,F_SETFL,flag);

    //写入,追加模式
    char *c2="3";
    res=write(fd,c2,strlen(c2));
     if(res==-1){
        perror("write");
        return -1;
    }
    close(fd);
}

执行后:21111111113

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值