第四讲 文件IO
用户空间的大量缓存
指针File结构体
0 标准输入
1 标准输出
2 标准出错
man open
必须要加入的头文件
SYNOPSIS
open c语言没有函数重载的内容却这样
… 可变参数
open 文件描述符
open打开一个或者创建一个文件
flags 打开的方式 多种打开方式的总和的话需要用位或
创建文件的话要加多一个权限
2>&1
对于2>&1的理解,2就是标准错误,1是标准输出,那么这条命令不就是相当于把标准错误重定向到标准输出么?
是的。为什么是&1而不是1,这里& 符号是什么?& 符号可以理解为引用(reference)。&1 就是对标准输出的引用。「我觉得可以理解为我们C语言里面的取地址符号,拿到标准输出的地址,往地址里面灌什么,标准输出就会给你输出什么」
nohup
nohup 指的是把命令放后台运行,并且不挂断的运行,他会把输出默认定向到文件nohup.out中
&
这个指令指的是在后台运行
4.2open函数的用法
fprintf发送格式化输出到流stream中
stderr是FileStream
标准输出将正常数据输出到标准输出文件
将错误信息送到标准错误文件
argc(参数个数) argv(参数的字符串数组的指针)
EXIT_FAILURE 可以作为exit ()的参数来使用,表示没有成功地执行一个程序
open(argv[1],O_RDONLY)
以只读的情况打开文件
open函数返回的错误信息
成功了返回文件描述符,错误了返回-1
错误类型
出错了的情况
open返回-1,打印错误信息
打印文件名,行数,错误号对应的信息
fprintf(stderr,"[%s][%d]:%s\n",__FILE__,__LINE__,strerror(errno))
打印错误信息strerror(errno)
如果没有出错就打印文件描述符
总的处理
open函数_>fcntl.h
errno
strerror string.h头文件
编译一下 gcc
打开一个文件
012文件描述符已经被系统占用了
0 标准输入
1标准输出
2标准错误
文件描述符是用来操作文件的一个标识,是一个数字。 ps -ef 可见所有进程,选择一个进程的 PID,如 22575
查看该进程所有的文件描述符:lsof -p 进程号
可见,没有对它们重定向的话,默认是指向 当前终端。
4.3read函数的用法
man read
#define E_EXIT(msg)\
do{\
fprintf(stderr,"[%s][%d]:%s:%s\n",__FILE__,__LINE__,msg,strerror(errno));\
exit(EXIT_FAILURE);\
}while(0)
fprintf()
char buf[BUF_SIZE];
int r = read(fd,buf,BUF_SIZE);
while(1){
//每一次读取之前应该将这块区域的内容清空
memset(buf,0x00,sizeof(buf));
//memset在一段内存中填充某个给定的值
int r=read(fd,buf,BUF_SIZE);
if(r==0){
break;
}
//r==0的时候就是读完的时候
printf("%s",buf);
if(r==-1){
/* fprintf(stderr,"[%s][%d]:%s\n",__FILE__,__LINE__,strerror(errno));
exit(EXIT_FAILURE);
*/
//异常退出
E_EXIT("read");
}
}
配置自己电脑的vim,配置一个根据个人习惯使用的.vimrc文件。我的有以下功能等,读者可以根据自己的
个人喜好去配置自己的vim。
4.4拷贝函数的write和close函数用法
man 2 write
write读取源文件内容,拷贝到目标文件
vim的分屏功能
argv[0]可执行文件
argv[1]源文件
argv[2]目标文件
int main(int argc,char *argv[]){
}
循环读取文件
记得memset
没有文件就要创建文件,open的参数里面要加上O_CREATE
umask
文件权限
原来的umask=0022 =》000 010 010 按位取反
和给出的数 110 110 110 进行按位与
110 110 110 &~000 010 010
=110 100 100
受umask的影响
gcc -o
vimdiff 查看两个文件是否相同
vimdiff open.c open.bk
按空格键将文件的内容全部显示出来
4.5 open其他选项用法
O_TRUNC
截断,如果一个文件已经存在
再往里面写内容将原来文件清空然后再写
正常情况下
如果文件有内容从前面覆盖
需要清空的话就将open函数与上一个O_TRUNC
man ftruncate
truncate清空内容
写日志
追加 O_APPEND
后面要讲的
O_EXCL 必须和creat选项(O_CREAT)一起,否则没有意义
当要创建的文件是存在的那么就会报错
如果没有处理报错是不会显示的
必须加上if(fd==-1)之后的操作
./a.out表示当前目录下的a.out文件。
a.out 是linux/unix环境下gcc编译源代码(c/c++)并连接产生的默认执行文件名。./a.out表示当前目录下的a.out文件。一个单独的点号指代当前文件路径。因为linux/unix搜索可执行文件的默认路径需要指定,没有./两个符号指定路径的话,新编译的文件操作系统找不到。
4.6lseek函数的用法
读写文件一般是按顺序读写的
lseek
随机读取
表示当前读到那个位置
man lseek
unistd.h头文件
close(fd)记得关闭打开的文件
write
这里不涉及内存字节的补齐的所以
34字节
这里
可以直接跳到stu.c的33行来修改内容
ls -l 查看文件的大小
dat 文件
把结构体数组整块搬过去的
想要读取dat 文件
dat 文件并不显示asc码的值
1.首先复制一份 stu.c的内容带read.c 删掉主函数的内容
2.主函数打开 stu.dat O_RDONLY
3.然后需要判断一下open返回的打开有没有出错
4.然后输出需要查询的第几个学生信息
5.lseek定位哪个学生
5.返回信息
写1不偏移
写2偏移一个
int num;
printf("%d",num);
scanf("%d",&num);
lseek(fd,(num-1)*sizeof(stu_t),SEEK_SET);
//定位到指定的结构体数组的位置
stu_t st;
//定义新的结构体数组
read(fd,&st,sizeof(stu_t));
//将数据读到指定的位置
printf("id=%d,name=%s\n",st.id,st.name);
如何求一个文件的大小
偏移到文件的结尾
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(int argc,char *argv[]){
int fd=open(argv[1],O_RDWR);
int r=lseek(fd,0,SEEK_END);
printf("file size = %d\n",r);
close(fd);
}
gcc编译一下
lseek的返回值就是新偏移的位置
./a.out copy.c 测试一下别的文件
ls -l test 查看test文件的详情
cat 只能显示能显示的
od 查看文件内容命令
od -c test 可以看到不可显示的
空洞文件
-lh以不同格式显示
od -c 查看文件的内容
du 看占用磁盘空间
4.8 竟态条件和文件描述符
追加
在open的时候加上append
文件描述符总是和文件一一对应的
一个进程能打开多少个文件是受限制的
open files 1024
可以修改的
文件描述符表示close exct
文件偏移量会变的
状态标志read write
对应磁盘 i-node表系统级
ls -i 每一个文件对应一个索引号,找到在磁盘哪个位置
输出重定向
文件描述符的复制
dup
输出重定向就是用了文件描述符复制这个功能
dup从小到大选择第一个没有被用到的文件描述符
dup2(oldfd,newfd)
dup2做的事和dup做的事是一样的
清空文件内容 > hehe
还有一个函数可以用 fctnl()
同时只能有一个一个
文件的锁
man fcntl
w等待
无 w报错
类型
范围
start开始的位置
len start都是0 表示锁全文
lock.l_type=F_UNLCK
gcc lock.c
阻塞了
打开文件的时候告诉内核应该怎样设置 状态标志
还有就是 程序执行过程中通过fcntl标志设置
缺省的就是阻塞的
4.11 文件系统
i节点表
数据是什么
数据指针
数据指针的指针
stat
获取文件的元数据信息
如何获取文件的信息
stat
man stat
st_nlink
硬链接数
uid 拥有者的id
gid 拥有者的组id
4.12文件类型和文件权限的获取
stat
在文件sys/stat.h头文件有
struct stat buf;
if(stat(argv[1],&buf)==-1){
//将信息装到struct 结构体中
perror(“stat”);
exit(EXIT_FAILURE);
//错误退出
}
上面
这么写是错的,下面这样写才是对的
我们,用户,本组,其他
ls -l命令的实现
stat 有 nlink 成员
getpwuid获得7列信息
需要用到 <pwd.h>
的头文件
如何根据组id获得组名
getgrgid
包含头文件 grp.h
getgrgid(buf.st_gid);
然后再用得到的对象->gr_name
获取系统的时间time()
转换成时间
man localtime
需要include<time.h>
获取时间
思考:如果文件是软连接呢?
4.14目录
操作目录的函数
man 3 opendir
循环读取文件
d_name
隐藏文件就是第一个文件是.
DIR *pd=opendir(".");
if(pd==NULL)
perror("opendir"),exit(1);
//z直接打印错误perror
struct dirent *dir=NULL;
while((pdir=readdir(pd))!=NULL){
if(pdir->d.name[0]=='.')
continue;
printf("%s\t",pdir->d_name);
}
printf("\n");
closedir(pd);
4.15 用链表显示目录内容
创建一个链表
文件项目
日志文件
等级
配置文件
#开始 说明
network -> ip port
log -> log_name log_level
找最优子问题
做几个假设
转移方程
什么时候定义初始条件
边界条件数组不能越界
从上到下
动态规划组成部分四:计算顺序