1.编写makefile文件
2._c库函数
3.系统IO函数
4.关于目录操作
5.dup/dup2
6.fcntl
Makefile代码管理工具,记录编译程序的步骤
1.Makefile的命名 makefile/Makefile:只能这两种之一 编写完后,直接 make 执行 2.makefile的规则: 规则中的三要素:目标、依赖、命令 方式1: 在文件中如下格式,目标两个字顶格,命令前有个Tab空格,如下图所示,命令可以是多条命令 目标:依赖条件 命令
方式2: 子目标和终极目标:如果有多条规则,默认最上方的目标为终极目标,其它为子目标 更新目标的原则: 特点:此方式下,更改某个c文件,make后不会重新编译所有c文件,而是只编译对应修改的文件,其它文件直接链接
3.makefile 工作原理 在更新时,首先检查每个.c文件和其生成的.o文件,如果.o文件的创建时间早于.c文件,说明.c文件进行了更新,则需要进行编译,否则不需要编译,只用链接就行,然后如果判断最终文件,如果最终文件的创建时间早于.o文件,则需要进行重新链接所有.o文件,更新最终目标文件
4.makefile中的变量 app:main.o sub.o mul.o gcc main.o sub.o mul.o -o app 模式匹配 %o:%c gcc -c $< -o $@ makefile自动变量 $<:规则中的第一个依赖 $@:规则中的目标 $^:规则中的所有依赖 这三个自动变量只能在规则的命令中使用,也就是上面gcc行 下图中,obj、target为自定义变量 $(obj):表示取obj的值
4.makefile函数:
所有makefile函数都有返回值
获取指定目录下的.c文件
src = $(wildcard .
//文件截断
fd = open("myhell",O_RDWR|O_TRUC);
if(fd==-1)
{
perrot("open file");
exit(1);
}
printf("fd = %dn",fd);
//关闭文件
int ret = close(fd);
printf("ret=%dn",ret);
if(ret==-1)
{
perror("close file");
exit(1);
}
}
2.read #includessize_t read(int fd,void* buf,size_t count); fd:文件描述符 buf:用户提供的缓冲区,通过malloc一个内存或者提供一个数组的地址,每次读完后数据存储在buf中 count:缓冲区大小 返回值: -1:读文件失败 0:文件读完了 >0的值:读出来的字节数 3.write ssize_t write(int fd ,const void *buf,size_t count); 返回值: -1:写入失败 4.close 返回值: 5.读大文件--写入另一个文件 read write -- 每次1个byte getc puts -- 每次读一个byte --效率更高 标准c库中有一个缓冲区,因此,使用c库函数,会先在用户区使用缓存收集一定数量的字节数的数据,当缓冲区满了之后再放入内核区(内核区也有缓存4KB),再写入磁盘中,而使用read和write,会每读一个字节就会经历2上述过程一次,频繁的状态转换导致效率更低
#include#include #include #include #include #include int main() { //打开一个文件 int fd= open("english.txt",O_RDONLY); if(fd==-1) { perror("open"); exit(1); } //创建一个新文件 int fd1 = open("newfile",O_CTEAT|O_WRONLY,0664); if(fd1==-1) { perror("creat"); exit(1); } //read file char buf[2048]={0} int count = read(fd,buf,sizeof(buf)); if(count ==-1) { perror("read"); exit(1); } while(count) { //将读出的数据写入另一个文件中 int ret=write(fd,buf,count) printf("write bytes %dn",count); //continue read file count = read(fd,buf,sizeof(buf)); } //close file close(fd); close(fd1); }
6.lseek:移动文件指针或者获取文件的长度 #include#include off_t lseek(int fd ,off_t offset,int whence) offset:文件指针的偏移量,这个偏移量指的是从whence起向后便宜的长度 whence: SEEK_SET:文件开始位置 SEEK_CUR:文件当前位置 SEEK_END:文件末尾位置 返回值:到偏移量的大小 作用 : 1.获取文件大小 2.移动文件指针 3.文件拓展
#include#include #include #include //close 头文件 #include //exit头文件 #include //perror头文件 int main() { int fd; //打开文件 fd=open("aa",O_RDWR); if(fd==-1) { perrot("open file"); exit(1); } //获取文件长度 int ret=lseek(fd,0,SEEK_END); printf("file length = %dn",ret); //在文件尾部向后拓展2000byte ret =lseek(fd,2000,SEEK_END);//也可以从当前位置拓展使用,SEEK_CUR printf("return value = %dn",ret); //实现文件拓展,需要再最后做一次写操作,写的数据会继续增加文件的大小,并且位于文件的末尾 write(fd,"a",1); close(fd); return 0; }
7.stat函数:获取文件信息 stat 文件名字 int stat(const cahr *path,struct stat *buf); 穿透(追踪)函数--软链接 int fstat(int fd,struct stat *buf); int lstat(const char *path,struct stat *buf); 不穿透函数(追踪) 第一个函数和第三个函数,如果读普通文件的大小,则是相同的,如果读软链接的大小,则第一个函数读的实际是映射到的文件的大小,而第二个实际是软链接的大小
像类似于struct stat *buf的参数一般都是传出参数,也就是在函数外定义一个该类型的结构体变量,取该变量的地址作为参数传入,变量所指的实际数据,会在函数内指定,然后在函数外,可以使用变量获取执行的结果数据。
在/etc/passwd中查看用户ID和组ID
可以通过truncate函数,传入一个比原文件大的长度,从而扩展文件大小
当需要一个临时文件时,可以先创建一个文件,然后使用unlink函数绑定改文件,当该文件被关闭时,文件就会被自动删掉
#include4.关于目录操作#include #include #include //close 头文件 #include //exit头文件 #include //perror头文件 int main() { int fd; //打开文件 fd=open("tempfile",O_CREAT|O_RDWR,0664); if(fd==-1) { perrot("open file"); exit(1); } //删除临时文件 int ret=unlink("tempfile"); //write file write(fd,"hello",5); //重置文件指针 ret =lseek(fd,0,SEEK_SET);//也可以从当前位置拓展使用,SEEK_CUR //read file char buf[24]={0}; int len=read(fd,buf,sizeof(buf)); //将结果写在屏幕上1--std_out标准输出屏幕,0--std_in ,2--std_error write(1,buf,len) close(fd); return 0; }
chdir函数相当于cd命令,用来切换目录,getwd相当与pwd用于获取当前路径
#include5.dup/dup2函数#include #include #include //close 头文件 #include //exit头文件 #include //perror头文件 int getFileNum(char* root) { //open dir DIR * dir = NULL; dir = opendir(root); if(dir==NULL) { perror("opendir"); exit(1); } //遍历当前打开的目录 struct dirent* ptr=NULL; char path[1024]={0}; int total=0; while((ptr=readdir(dir))!= NULL) { //过滤掉 . 和 .. if(strcmp(ptr->d_name,".")==0||strcmp(ptr->d_name,"..")==0) { continue; } if(ptr->d_type==DT_DIR) { //递归读目录 sprintf(path,"%s/%s",root,ptr->d_name) total=getFileNum(path); } //普通文件 if(ptr->d_type==DT_REG) { total++; } } colsedir(dir); return total; } int main(int argc,char * argv[]) { fi(argc<2) { printf("./a.out dirn") exit(1); } int total=getFileNum(argv[1]); printf("%s has file number %dn",argv[1],total); return 0; }
复制现有的文件描述符 dup int dup(int oldfd); 返回新的文件描述符,该文件描述符为文件描述符列表中最小的没有被占用的文件描述符 dup2 int dup2(int oidfd,int newfd); 1.old,new不同,如果new是一个被打开的文件描述符,在拷贝前会先关掉new对应的文件,调用后,old和new指向统一个文件,该文件,是old原来对应的文件,对于每个文件描述符,都需要调用close(new),close(new); 返回值为-1时,拷贝失败。 2.如果old与new是同一个文件描述符,不会关掉new,会直接返回这个文件描述符6.fcntl函数
改变已打开的文件的属性 例如: 打开时只读 修改文件属性:添加追加O_APPEND
当cmd为F_GETFL时,第三个参数为0
#include#include //close 头文件 #include //exit头文件 #include //perror头文件 int main() { int fd; //测试字符串 char *p="我们是一个中国特色社会主义国家" char *q="呵呵,社会主义好啊。。。。。" //打开文件 fd=open("tempfile",O_WRONLY); if(fd==-1) { perrot("open file"); exit(1); } if(write(fd,p,strlen(p))==-1) { perror("write"); exit(1); } //使用F_GETFL命令得到文件状态标志 flag = fcntl(fd,F_GETFL,0) if(flag==-1) { perrot("fcntl"); exit(1); } //将文件标志添加“追加写”选项 flag|=O_APPEND; //将文件状态改为追加写 if(fcntl(fd,F_SETFL,flag)==-1) { perror("fcntl -- append write"); exit(1); } //再次输入新内容,该内容会追加到旧内容的后面 if(write(fd,q,strlen(q))==-1) { perror("write again"); exit(1); } close(fd); return 0; }



