Linux系统编程—文件操作

文件的属性与权限

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变量如下:
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值