第一章
1 动态库静态库
制作并使用静态库
库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用 者一些可以直接拿来用的变量、函数或类。
库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。
库文件有两种,静态库和动态库(共享库),区别是:静态库在程序的链接阶段被复制到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。
库的好处:1.代码保密 2.方便部署和分发
实验:
制作静态库
[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
制作并使用动态库
实验:
制作动态库
[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
添加
再从新开一个终端
[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
3 修改ld.so.cache
[wt@study library]$sudo vim /etc/ld.so.conf
[wt@study library]$ sudo ldconfig
4.将动态库放在 /lib,/usr/lib下,但不推荐
总结:
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
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
version4:
使用函数
[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
执行完后生成可执行文件app而.o文件可以删除:
[wt@study lesson07]$ vim Makefile
[wt@study lesson07]$ make clean
rm ./mult.o ./main.o ./add.o ./div.o ./sub.o -f
若当前文件夹下有clean文件,则不会执行,可以添加.PAONY:clean表明clean是伪目标,不会生成clean文件,则就不会根clean对比了
3.GDB调试
list或者l命令,不是list/l命令,
show list/listsize 显示的是默认list会显示多少行代码
可以通过设置 list或者listsize来改变list/l显示的代码行数
4.文件IO
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 7月 12 19:55 a.out
-r----x--t. 1 wt wt 0 7月 12 20:14 a.txt
-rwxrwxr-x. 1 wt wt 8496 7月 12 19:58 main
-rw-rw-r--. 1 wt wt 539 7月 12 20:14 main.c
-rwxrwxr-x. 1 wt wt 8496 7月 12 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 7月 12 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 7月 12 22:27 1.txt
-rwxrwxr-x. 1 wt wt 8600 7月 12 22:27 main
-rw-rw-r--. 1 wt wt 374 7月 12 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()函数
可以通过与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;
}
文件属性操作函数
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 7月 13 17:03 access
-rw-rw-r--. 1 wt wt 202 7月 13 17:03 access.c
[wt@study lesson13]$ touch a.txt
[wt@study lesson13]$ ls -l
总用量 16
-rwxrwxr-x. 1 wt wt 8504 7月 13 17:03 access
-rw-rw-r--. 1 wt wt 202 7月 13 17:03 access.c
-rw-rw-r--. 1 wt wt 0 7月 13 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 7月 13 17:03 access
-rw-rw-r--. 1 wt wt 202 7月 13 17:03 access.c
-rwxrwxr-x. 1 wt wt 0 7月 13 17:10 a.txt
-rwxrwxr-x. 1 wt wt 8448 7月 13 17:11 chmod
-rw-rw-r--. 1 wt wt 152 7月 13 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 7月 13 17:03 access
-rw-rw-r--. 1 wt wt 202 7月 13 17:03 access.c
-rwxrwxr-x. 1 wt wt 186 7月 13 17:19 a.txt
-rwxrwxr-x. 1 wt wt 8448 7月 13 17:11 chmod
-rw-rw-r--. 1 wt wt 152 7月 13 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 7月 13 17:03 access
-rw-rw-r--. 1 wt wt 202 7月 13 17:03 access.c
-rwxrwxr-x. 1 wt wt 10 7月 13 17:33 a.txt
-rwxrwxr-x. 1 wt wt 8448 7月 13 17:11 chmod
-rw-rw-r--. 1 wt wt 152 7月 13 17:11 chmod.c
-rwxrwxr-x. 1 wt wt 8456 7月 13 17:33 trcuncate
-rw-rw-r--. 1 wt wt 164 7月 13 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;
}
}
//若是扩展的。则会用空字符填
目录操作函数
#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);
实验:统计目录下有多少个普通文件
#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()函数
#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()函数
#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