将近日学习Linux基础编程,系统编程,网络编程的word笔记搬运过来,图片无法直接粘贴,就丢失掉了。
日后工作学习中使用与扩充维护还是word笔记
这篇文章图片很多,亏大了。基础编程day03
内容简介:
学习目标:
1 掌握read/write/lseek函数的使用
2 掌握stat(穿透)/lstat函数的使用
3 了解文件属性相关的函数使用
4 了解目录操作相关的函数的使用
5 掌握目录遍历相关函数的使用,和读文件类似打开,读,关闭
6 掌握dup,dup2函数的使用,复制文件描述符,多个文件描述符指向同一个磁盘文件
7 掌握fcntl函数的使用,在文件打开后追加属性,有5大类功能
内容简介:
lseek
对文件指针set,cur,append,返回的是off_t与文件头部的距离
stat函数
stat命令,struct stat
文件操作
access,chmod,chown,truncate
目录操作
rename,chdir,getcwd,mkdir,rmdir
目录遍历
opendir,DIR *,struct dirent,readdir,记得关闭
dup复制文件描述符
dup2恋旧
fcntl
复制文件描述符,改变文件状态(读写属性不能改)
复习:
1makefile
一个规则
目标:依赖
(tab缩进)命令
可以有多个规则
make 直接生成终极目标
第一个规则对应的目标
make+子目标的名字
就会生成子目标,和终极目标没关系
工作原理
依赖不存在:
向下查找子规则,找到了用来生成依赖的规则,执行里面的命令
依赖存在->更新检查
更新条件:目标时间<依赖时间
两个函数:
wildcard搜索指定目录下指定的文件
src = $(wildcard ./src/*.c)
src= ./src/a.c ./src/b.c ./src/c.c
patsubst
obj = $(patsubst %.c, %.o, $(src) ) ;
把*.c都替换为*.o,*.c是从src中得到的
obj= ./src/a.o ./src/b.o ./src/c.o
三个自动变量
$@:规则中的目标
$<:规则中的第一个依赖
app:a.o b.o c.o
gcca.o b.o c.o –o app
$^:规则中的所有依赖
模式规则:像公式一样,每遇到需要生成.o文件,就来这里套用
%.o:%.c
gcc –c &< -o &@
清空项目
声明伪目标:说明这个目标是个假的目标,不需要做更新检查
.PHONY:clean
clean:
-rm*.o
目标不是必须在命令中生成,只是一个格式
作业:一个很大的文件,open数据读出来,read读出来后写入另一个文件
通过read的返回值可以判断是否读完(>0)
write函数第三个参数为buf中有效的字节数,如果使用strlen函数,必须要保证buf中最后一个字符是\0,如果不能保证,那么请用read函数的返回值来作为有效字节数。
或:把buf[4095]初始化为\0,且read的时候sizeof(buf)-1
通过read的返回值判断是否到达文件尾部
系统函数调用失败,返回值一般都是-1
erro no是系统函数库的全局变量
perror(const char *s)根据errno的值打印相应的错误信息,s会先被打印。一般是函数的名字,这样在打印错误信息时,能快速定位错误位置。
lseek
函数原型:off_t lseek(int fd, off_t offset, int whence);
SEEK_SET:头部
SEEK_CUR:当前位置
SEEK_END:尾部
使用:
文件指针移动到头部
lseek(fd,0, SEEK_SET); 返回值是0
获取文件指针当前位置
intlen = lseek(fd, 0, SEEK_CUR);
获取文件长度
intlen = lseek(fd, 0, SEEK_END);
文件拓展
文件原大小100k,拓展为1100k,
lseek(fd,1000, SEEK_END);
write(fd,“a”, 1);若想拓展成功,必须进行一次写操作,往文件尾部写一个数据
作用:迅雷下载的时候,文件10G,刚开始下载的时候,文件就是10G,就是使用了文件拓展:1占位作用2方便多线程指针后移
阻塞和非阻塞
阻塞:代码执行到这里,就不再向下执行,只有条件满足才会继续向下执行。
阻塞非阻塞是文件的属性还是read等函数的属性:文件的属性
STDIN_FILENO是标准输入的文件描述符
终端会被抽象为设备文件,放在dev下,tty就是不同的终端dev/tty就是当前终端
ld…未找到命令出现的原因:
默认bash是前台程序
./block_read启动了一个程序,前台程序变成了./block_read,bash变成了后台程序,
./block_read等待用户输入10个字符,实际输入的>10个字符,剩下的还在缓冲区中,read解除阻塞读缓冲区数据,write函数完毕后,程序结束
bash从后台程序变为前台程序,检测到了缓冲区中有数据,把缓冲区的数据作为shell命令进行解析
打开终端,默认的就是阻塞的,O_NONBLOCK设置的是打开文件的状态
读终端的时候没有数据,errno=EAGAIN,可以sleep(3),write(STDOUT_FILENO, “try again”, strlen(“try again”) ) ;
阻塞非阻塞是文件的属性
读写普通文件:hello.c
默认不阻塞
读写终端设备:dev/tty
默认阻塞
管道
套接字
stat函数,获得文件信息
stat命令的效果(shell命令):
ctime atime mtime
最近改动:文件属性改变,就叫改动
使用stat函数头文件:
1<sys/types.h> 2<sys/stat.h> 3<unistd.h>
stat函数声明
intstat(const char *pathname, struct stat *buf) ;成功返回0,失败返回-1
通过*buf指针修改实参的值
stat结构体:
注意蓝色的字,是用来做&操作的,过滤掉无关位
与掩码做&操作,作用:针对某功能,过滤其他位
(st.st_mode & S_IFMT) == S_IFREG
if(st.st_mode & S_IFREG) 判断该位是否为1
穿透
int lstat(const char *pathname, struct stat*buf) ;
与stat区别,读软连接文件(ln–s main.c m.s)的时候,读到的是软连接.s文件的信息,而stat函数读取的链接文件指向的文件的属性,称为追踪或穿透。
应用场景:实现ll m.s的时候
int fstat(int fd, struct stat *buf);
通过文件描述符获取文件属性。
文件操作:access,chmod,chown,truncate,
获取当前用户对文件权限int access(const char *pathname, int mode);
头文件:unistd.h
检测当前用户对文件的权限,R_OK,W_OK,X_OK,
判断文件是否存在F_OK(是否存在)
有就返回0,没就返回-1
修改文件权限int chmod(const char*pathname, int mode);
filename:文件名
mode:八进制数
strtol把字符串转化为不同进制的数字
修改文件所有者所属组int chown(const char *path, uid_t owner, gid_t group);
其中owner和group都是ID号
etc/passwd,etc/group中可以找到ID号
修改文件大小int truncate(const char *path, off_t length);
参数:
length是文件的最终大小
比原来小,删除后边的部分
比原来大,向后拓展,加占位符,空洞
path:文件名
目录操作:rename,chdir,getcwd,mkdir,rmdir
目录重命名:
intrename(const char *oldpath, const char *newpath);
修改当前进程(应用程序)的路径
intchdir(const char *path);
参数:切换到的目录
获取当前进程的工作目录
chargetcwd( char *buf, size_t size);
通过*buf修改实参的值,将结果放入buf指向的内存中,size是buf的大小
创建目录mkdir
intmkdir(const char *pathname, mode_t mode);
参数:
pathname创建的目录名
mode:目录权限,八进制数实际权限& ~u_mask &0777
删除空目录:
int rmdir(constchar *pathname);
参数:空目录的名字
目录遍历相关函数opendir,dirent,closedir
1 打开一个目录DIR *opendir(constchar *name);
参数:目录名
返回值:指向目录的指针
DIR*与FILE*类似,后者是fopen得到的
2 读struct dirent*readdir(DIR *dirp);
d_type判定文件的类型
循环读取目录
一个目录下有三个文件,需要循环地去读
opendir之后,while(readdir() ){} ,readdir返回null后,就是文件读完了
目录是树结构。
关闭目录
intclosedir(DIR *dirp) ;
//读指定目录中文件的个数
int get_file_num(char *root)
{
inttotal = 0;
//读目录
DIR *dir = opendir(root);
if(dir== NULL)
{
perror(“opendirerror”);
exit(1);
}
struct dirent *ptr = NULL;
while( (ptr = readdir(dir) ) != NULL )
{
//不处理.和..
if(strcmp(“.”, ptr->d_name) == 0 || strcmp(“..”, ptr->d_name) == 0 )
{
continue;
}
//判断是不是普通文件
if(ptr->d_type== DT_REG )
{
total++;
}
//如果是目录,递归
if( ptr->d_type == DT_DIR)
{
//求出子目录
charpath[1024] = {0};
sprintf(path,“%s/%s”, root, ptr->d_name) ;
total= total + get_file_num(path);
}
}
//关闭目录
closedir(dir);
returntotal ;
}
命令行传参:参数传给argv[],argv[0]是可执行程序的名字,你传的参数从argv[1]开始。
argc是argv[]中元素的个数
文件描述符的复制(但是文件指针还是只有一个)
int dup(int oldfd) ;
oldfd:要复制的文件描述符
返回值:新的文件描述符(空闲的文件描述符当中最小的)
dup调用成功:
有两个文件描述符指向同一个文件
f_count表示有多少个文件描述符指向这个文件
int dup2(int oldfd, int newfd) ; 怀旧
能控制新的文件描述符是哪个
oldfd->hello
newfd->world
dup2(oldfd,newfd);
newfd->hello;oldfd->hello
文件描述符的重定向:
假设newfd已经指向了一个文件,首先断开(close)与那个文件的链接newfd指向oldfd指向的文件
newfd与oldfd指向同一个文件,则不会执行先断开再建立的操作。
fcntl:改变已经打开的文件的属性
变参函数
复制一个已有的文件描述符
intret = fcntl(fd, F_DUPFD);
获取和设置文件状态标志,RDONLY?WRONLY?
open的flags参数
1获取文件状态标识
intflag = fcntl(fd, F_GETFL);
2设置文件状态标识符
flag = flag | O_APPEND;
fcntl(fd,F_SETFL, flag);
可以更改的几个标识:O_APPEND, O_NONBLOCK
错误操作:
open(“temp”,O_RDONLY);
需要设置文件为O_RDWR,这是不可以的