文件的属性与权限
1.文件的权限与属性
(1)管理文件的权限
命令:chmod
chmod [ugoa] [[+/-/=] [rwx]...] [文件名1...]
- u:所有者
- g:所属组
- o:其他人
- a:以上三者都有
- +:增加权限
- -:取消权限
- =:唯一审定权限
2.文件管理
三种常用实现途径:
- 直接进行文件系统底层操作
- 通过调用shell程序
- 借助系统调用实现
(1)系统调用
(2) 打开文件、新建文件和关闭文件操作
打开文件:使用系统函数open(),作用是建立一个文件描述符,其他函数可以通过文件描述符对指定文件进行读写。打开成功返回正整数,失败返回**-1**。
open(文件路径,标志)
标志:
- O_RDONLY:只读
- O_WRONLY:只写
- O_RDWR:可读可写
副标志如下:
创建新文件同时可设置文件的权限,函数的形式为:
open(文件路径,标志,权限标志)
新建文件的另一个函数是create(),一般形式为
create(路径,umask)
umask变量如下:
文件不需要是可用close()函数关闭,成功返回0,否则返回-1。
下面的实例演示相关文件操作。程序的逻辑为:指定一个路径,若该文件存在,输出提示信息,关闭文件,如果不存在,则新建文件并设置文件属性,输出提示信息,然后关闭该文件。
#include<fcntl.h> //提供open()
#include<sys/types.h> //提供mode_t类型
#include<sys/stat.h> //提供open()函数的符号
#include<unistd.h> //提供close()函数
#include<stdio.h>
using namespace std;
int main()
{
int f;
const char *f_path="test";
mode_t f_attrib; //声明mode_t型变量,保存文件属性
f_attrib=S_IRUSR | S_IWUSR |S_IRGRP |S_IWGRP | S_IROTH; //为umask变量赋值
f=open(f_path,O_RDONLY);
if (f==-1)
{
f=open(f_path,O_RDONLY | O_CREAT,f_attrib);
if(f!=-1)
puts("创建一个新文件");
else
{
puts("无法创建新文件,程序退出");
return -1;
}
}
else
puts("文件打开成功");
close(f);
return 0;
}
使用g++编译器进行编译,随后调用两次,结果如下
mode_t型变量f_attrib赋值的方法使用了按位计算操作,将表示文件权限的常量进行按位或计算,如图
(3)文件状态和属性操作
- fsfat(文件标识符,struct stat *buf):用于返回一个已打开文件的状态和属性信息
- lstat(路径,struct stat *buf):当文件是一个符号链接时,lstat返回该符号链接本身的信息
- stat(路径,struct stat *buf):当文件时一个符号链接时,返回该链接指向文件的信息
结构体struct stat类型是stat.h函数库提供的一种用于保存文件类型的结构体。其成员意义如下:
其中,st_mode与其他成员相比要复杂许多,必须使用标志与之进行按位与运算才能获得相应信息。st_mode的标志见下表:
修改文件权限的系统调用函数是chmod(路径,umask)。修改成功返回0,失败返回-1。
下面通过示例演示这几个函数用法
#include<fcntl.h> //提供open()
#include<sys/types.h> //提供mode_t类型
#include<sys/stat.h> //提供open()函数的符号
#include<unistd.h> //提供close()函数
#include<stdio.h>
#include<stdlib.h>
using namespace std;
int main()
{
int f;
const char *f_path="test02";
mode_t f_attrib;
struct stat *buf=new struct stat;
f_attrib=S_IRUSR | S_IWUSR |S_IRGRP |S_IWGRP | S_IROTH;
f=creat(f_path,f_attrib);
if(f==-1)
{
puts("文件创建失败");
return 1;
}
else
{
puts("文件创建成功");
}
fstat(f,buf);
if(buf->st_mode & S_IRUSR)
puts("所有者拥有读权限");
if(buf->st_mode & S_IRGRP)
puts("所属组拥有读权限");
close(f);
chmod(f_path,0711);
stat(f_path,buf);
if(buf->st_mode & S_IWUSR)
puts("所有者拥有写权限");
if(buf->st_mode & S_IWGRP)
puts("所属组拥有写权限");
delete buf;
return 0;
}
八进制常量0711代表所有者拥有读、写和执行权限。
注意,不能用malloc动态分配内存,因为其为函数类型或不完全类型。编译后运行结果如下:
(4)目录操作
新建目录操作可使用mkdir()函数,一般形式为
mkdir(路径,umask)
当目录被成功创建,函数返回0,否则为-1
获得当前工作目录的操作可使用函数getcwd(),一般形式为
getcwd(char *buf,size_t size)
*buf是存放当前目录的缓冲区,size是缓冲区大小,若函数返回当前目录的字符串长度超过size规定的大小,将返回NULL。
执行程序的工作目录就是当前子目录,若要改变执行程序的工作目录,可使用函数chdir(),其作用如同shell里的cd命令,一般形式为
chdir(路径)
与扫描子目录相关的函数被封装在头文件dirent.h中。它们使用一个名为DIR的结构作为子目录处理的基础。这个结构的指针指向的内存空间被称之为子目录流,相关操作如下表
下面的例子设计一个可遍历子目录中所有文件的函数,并生成一个可用于遍历选定目录的文件。
//file03_1.h
#ifndef SCAN_DIR
#define SCAN_DIR
#include<fcntl.h> //提供open()
#include<sys/types.h> //提供mode_t类型
#include<sys/stat.h> //提供open()函数的符号
#include<unistd.h> //提供close()函数
#include<stdio.h>
#include<stdlib.h>
#include<dirent.h> //提供目录流操作函数
#include<string.h>
void scan_dir(char *dir,int depth);
#endif
//file03_2.cpp
#include"file03_1.h"
void scan_dir(char *dir,int depth)
{
DIR *dp;
struct dirent *entry; //定义dirent结构指针保存后续目录
struct stat statbuf; //定义statbuf结构保存文件属性
if((dp=opendir(dir))==NULL)
{
puts("无法打开该目录");
return;
}
chdir(dir); //切换到当前目录中去获取下一级目录信息
while((entry=readdir(dp))!=NULL)
{
lstat(entry->d_name,&statbuf); //获取下一级成员属性
if(S_IFDIR&statbuf.st_mode) //判断下一级成员是否是目录
{
if (strcmp(".",entry->d_name)==0||strcmp("..",entry->d_name)==0)
continue; //如果获得的成员是符号“.”和“..”,跳过本次循环
printf("%*s%s/\n",depth,"",entry->d_name);
scan_dir(entry->d_name,depth+4); //递归调用自身,扫描下一级目录
}
else
printf("%*s%s\n",depth,"",entry->d_name); //输出属性不是目录的成员
}
chdir(".."); //回到上一级目录
closedir(dp);
}
//flie03_3.cpp
#include"file03_1.h"
#include<iostream>
using namespace std;
int main(int argc,char* argv[])
{
if(argc>2)
cout<<"只可扫描一个目录"<<endl;
else
{
cout<<argv[1]<<endl;
scan_dir(argv[1],0);
cout<<"扫描结束"<<endl;
}
return 0;
}
scan_dir的作用是遍历目录,将其所有的子目录和文件输出到终端上。遍历子目录采用递归调用,首先判断子目录流指针指向的文件是否为目录文件,如果是,则递归遍历子目录,如果不是,则输出文件名,继续遍历当前目录,知道子目录流指向NULL。depth参数的作用是在子目录前增加空格的数量,更容易显示目录层次。
编译后运行结果如下:
(5)删除目录或文件操作
删除目录操作函数:
rmdir(路径)
该函数必须是在该目录下没有子目录或文件的情况下才能运行。
删除文件操作函数:
unlink(路径)
在Linux系统中创建临时文件可使用mkstemp()函数,一般形式是:
mkstemp(文件名XXXXXX)
会以可读写模式和0600权限来打开该文件,如果该文件不存在则会建立。打开该文件后其文件描述符会返回,如果文件打开或创建失败则返回NULL。需要注意的是,文件名必须是用字符串XXXXXX结尾。
(6)错误处理
错误信息将以代码的形式保存在系统变量errno中。很多函数通过改变errno变量的值输出标准错误信息编码,这些错误信息被保存在头文件errno.h内。
perror()函数的作用是将标准错误信息字符串输出到终端上,并为其增加一个说明,如
perror("文件操作")
如果执行失败,此函数被调用,会输出类似如下信息:
文件操作:No such file or directory