在lesson9目录下,open.c使用函数1(上面列表的第一个),create.c使用函数2(上面列表的第二个)。
int open(const char *pathname, int flags, mode_t mode);//可变参数
参数:
flags:对文件操作权限的设置和其他设置。flags参数是一个int类型的数据,占4个字节,32位
flags 32个位 每一位都是一个标志位
- 必选项:O_RDONLY, O_WRONLY, or O_RDWR. 三个操作互斥
These request opening the file read-only, write-only,or read/write
- 可选项:O_CREAT 文件不存在,创建新文件
mode:八进制的数,表示用户对新创建文件的操作权限,比如:0775
最终的权限是:mode & ~umaskumask的作用是抹去某些权限
返回值:
open(), openat(), and creat() return the new file descriptor,or -1 if an error occurred
create.c中的代码如下:
#include
#include
#include
#include
#include
int main(){
//创建一个新的文件
int fd= open("create.txt",O_RDWR | O_CREAT,0777);
if(fd==-1){
perror("open");
}
//关闭
close(fd);
return 0;
}
需要注意的是函数2中的mode是一个八进制数,该数表示用户对新创建文件的操作权限,比如:0775,但最终的权限是由mode & ~umask决定的,umask的作用是抹去某些权限。在create.c的代码中,我们设置了mode是0777,但是对create.c编译运行之后产生的create.txt文件的操作权限如下:
操作权限为:rwx rwx r-x(111 111 101,即775),我们设置的mode为0777,但是实际文件的操作权限为0775,可见实际操作权限并不仅仅由我们设置的mode决定。
新建文件夹lesson10:
#include
ssize_t read(int fd, void *buf, size_t count);
#include
ssize_t write(int fd, const void *buf, size_t count);
参数:
fd:文件描述符,通过文件描述符操作某个文件
buf:要往磁盘写入的数据
返回值
lesson10目录下有个大小为129772的英文txt文档,接下来使用read和write两个函数实现复制操作。
copyfile.c:
#include
#include
#include
#include
#include
int main(){
//通过open打开english.txt文件
/*
查阅文档可知,需要导入三个头文件
#include
#include
#include
*/
int srcfd=open("english.txt",O_RDONLY);
if(srcfd==-1){
perror("open");
return -1;
}
//创建一个新文件
int destfd=open("cpy.txt",O_WRONLY|O_CREAT,0664);
if(destfd==-1){
perror("open");
return -1;
}
//频繁读写操作
char buf[1024]={0};
int len=read(srcfd,buf,sizeof(buf));
//len>0表示文件中还有数据尚未被读取
while((len=read(srcfd,buf,sizeof(buf)))>0){
write(destfd,buf,len);
}
//关闭文件
close(destfd);
close(srcfd);
}
编译链接c文件获得可执行文件copy,并运行copy:
#include
int fseek(FILE *stream, long offset, int whence);//标准c库的函数
#include
#include
off_t lseek(int fd, off_t offset, int whence);//linux系统函数
lseek() repositions the file offset of the open file description associated with the file descriptor fd to the argument offset according to the directive whence as follows:
参数:
返回值:返回文件指针的位置
实例:
lesson11目录下有hello.txt和lseek.c两个文件,我们在lseek.c文件中对hello.txt的长度进行拓展。
#include
#include
#include
#include
#include
int main(){
int fd=open("hello.txt",O_RDWR);
if(fd==-1){
perror("open");
return -1;
}
//拓展文件长度
int ret= lseek(fd,100,SEEK_END);
if(ret==-1){
perror("lseek");
return -1;
}
//写入一个空数据(最好写入一个空数据,不然不能拓展文件长度)
write(fd," ",1);
//关闭文件
close(fd);
return 0;
}
编译链接lseek.c文件生成可执行文件并执行,可以看到hello.txt文件长度增加了101(使用NULL填充了100次,空格填充了一次)。
使用lseek拓展文件长度,可以用于下载任务。下载一个大小为2G的文件时,先使用lseek拓展出一个大小为2G的空间,再将下载的文件填充到该空间。
创建目录lesson12
#include
#include
#include
int stat(const char *pathname, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);//用来获取软链接文件的信息
参数:
stat结构体:
struct stat {
dev_t st_dev; // 文件的设备编号
ino_t st_ino; // 节点 mode_t st_mode; // 文件的类型和存取的权限
mode_t st_mode; // 文件的类型和存取的权限
nlink_t st_nlink; // 连到该文件的硬连接数目
uid_t st_uid; // 用户ID
gid_t st_gid; // 组ID
dev_t st_rdev; // 设备文件的设备编号
off_t st_size; // 文件字节数(文件大小)
blksize_t st_blksize; // 块大小
blkcnt_t st_blocks; // 块数
time_t st_atime; // 最后一次访问时间
time_t st_mtime; // 最后一次修改时间
time_t st_ctime; // 最后一次改变时间(指属性)
}
S_IFMT八进制数值转为二进制为1111 0000 0000 0000 st_mode&S_IFMT判断文件类型
在lesson12中编写stat.c代码查看文件a.txt的内容:
#include
#include
#include
#include
int main(){
struct stat statbuf;
int ret=stat("a.txt",&statbuf);
if(ret==-1){
perror("stat");
return -1;
}
printf("size: %ld\n",statbuf.st_size);
return 0;
}
编译运行stat.c程序,运行结果如下:
创建软连接文件b.txt 链接到a.txt文件
通过ll和stat命令查看b.txt的实际大小是5字节
在程序中stat查看b.txt获取的是a.txt的信息,lstat查看b.txt才获取到b.txt的信息
ls -l命令能获取目录下所有文件的权限 修改时间等信息。
ls-l.c代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
//模拟实现ls -l指令
//-rw-rw-r-- 1 ccb ccb 12 11月 9 15:04 a.txt
/*
argc是参数数量,系统会根据传入的参数自动赋值
一般输入有两个一个是可执行文件路径,一个是文件名称
*/
int main(int argc,char * argv[]){
//判断输入的参数是否正确并给出提示
if(argc<2){
printf("%s filename\n",argv[0]);
return -1;
}
//通过stat函数查看用户指定文件的信息
struct stat st;
int res= stat(argv[1],&st);
if(res==-1){
perror("stat");
return -1;
}
//获取文件权限和文件类型
char parms[11]={0};//用于保存“-rw-rw-r-- ”字符串
switch (st.st_mode&S_IFMT)
{
case S_IFLNK:
parms[0]='l';//软链接
break;
case S_IFDIR:
parms[0]='d';//目录
break;
case S_IFREG:
parms[0]='-';//普通文件
break;
case S_IFBLK:
parms[0]='b';//块设备
break;
case S_IFSOCK:
parms[0]='s';//套接字
break;
case S_IFCHR:
parms[0]='c';//字符文件
break;
case S_IFIFO:
parms[0]='i';//管道文件
break;
default:
parms[0]='?';
break;
}
//判断文件访问权限
//文件所有者
parms[1]=(st.st_mode&S_IRUSR)?'r':'-';
parms[2]=(st.st_mode&S_IWUSR)?'w':'-';
parms[3]=(st.st_mode&S_IXUSR)?'x':'-';
//文件所在组
parms[4]=(st.st_mode&S_IRGRP)?'r':'-';
parms[5]=(st.st_mode&S_IWGRP)?'w':'-';
parms[6]=(st.st_mode&S_IXGRP)?'x':'-';
//其他人
parms[7]=(st.st_mode&S_IROTH)?'r':'-';
parms[8]=(st.st_mode&S_IWOTH)?'w':'-';
parms[9]=(st.st_mode&S_IXOTH)?'x':'-';
//硬链接数
int linkNum=st.st_nlink;
//文件所有者
char * fileUser=getpwuid(st.st_uid)->pw_name;
//文件所在组
char * fileGroup=getgrgid(st.st_gid)->gr_name;
//文件大小
long int fileSize=st.st_size;
//获得修改时间
char * editTime=ctime(&st.st_mtime);
char mtime[512]={0};
strncpy(mtime,editTime,strlen(editTime)-1);//去掉editTime最后的换行符
char buf[1024];
sprintf(buf,"%s %d %s %s %ld %s %s",parms,linkNum,fileUser,fileGroup,fileSize,mtime,argv[1]);
printf("%s\n",buf);
return 0;
}
编译运行之后结果如下: