文章目录
1.新接口
int stat(const char *pathname, struct stat *statbuf);
struct stat
{
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
struct timespec st_atim; /* Time of last access 最后一次访问*/
struct timespec st_mtim; /* Time of last modification 最后一次修改*/
struct timespec st_ctim; /* Time of last status change 最后一次状态改变*/
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
函数讲解
stat 函数
int stat(const char *pathname, struct stat *statbuf); 函数用于获取指定文件的状态信息,并将其存储在 struct stat 类型的 statbuf 中。
参数说明
pathname:文件的路径名。
statbuf:指向 struct stat 类型的指针,用于接收文件的状态信息。
返回值
成功时返回 0。
失败时返回 -1,并设置 errno 来指示错误类型。
回顾缺省参数
在函数调用时,参数是自左向右逐个匹配的,如果缺省参数不是从右往左给,当实参和形参个数不一致时,可能会导致无法明确参数的对应关系。
回顾C++IO流ifstream
#include <vector>
#include <string> // for string
#include <fstream> // for ifstream
#include <cstring> // for cerr
#include <iostream>
int main()
{
// 打开文件
// std::ifstream file("test1.txt", std::ios::binary|std::ios::in);
std::ifstream file("test1.txt", std::ios::binary);
if (!file.is_open())
{
std::cerr << "Failed to open the file." << std::endl;
return 1;
}
// 读取文件内容到string对象ok
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
// 逐行读取ok
// std::string content;
// std::string line;
// while (std::getline(file, line))
// {
// content += line;
// content += "\n"; // getline不读\n
// }
// read函数ok
// std::string content;
// content.resize(100);
// file.read(&content[0], 100);
// 输出读取的内容(可选)
std::cout << content << std::endl;
// 关闭文件
file.close();
return 0;
}
回顾Linux三个系统时间
一、文件时间的作用和应用场景
在 Linux 系统中,文件的最后一次访问时间(atime)、最后一次修改时间(mtime)和最后一次状态改变时间(ctime)都具有重要的作用和特定的应用场景。
(一)最后一次访问时间(atime)
- 作用:记录文件内容被读取的时间。
- 应用场景:
- 可以用于监测文件是否被读取,例如某些安全监控系统中,通过检查 atime 来判断是否有异常的文件访问行为。
- 对于缓存系统,可根据 atime 来决定是否需要更新缓存内容。
(二)最后一次修改时间(mtime)
- 作用:反映文件内容的最后修改时刻。
- 应用场景:
- 备份系统可以依据 mtime 来确定哪些文件需要备份。
- 版本控制系统中,通过对比 mtime 来判断文件是否有更新,从而决定是否需要进行版本控制操作。
(三)最后一次状态改变时间(ctime)
- 作用:记录文件的 i 节点(inode)最后一次被修改的时间。
- 应用场景:
- 当文件的属性(如权限、所有者等)发生变化时,ctime 会更新,这对于权限管理和审计非常有用。
- 一些系统管理工具可以利用 ctime 来监测文件系统的状态变化。
C++17std::experimental::filesystem
c++17std::experimental::filesystem
exists
show case
#include <cstdint>
#include <experimental/filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::experimental::filesystem;
void demo_exists(const fs::path& p, fs::file_status s = fs::file_status{})
{
std::cout << p;
if (fs::status_known(s) ? fs::exists(s) : fs::exists(p))
std::cout << " exists\n";
else
std::cout << " does not exist\n";
}
int main()
{
fs::create_directory("sandbox");
std::ofstream("sandbox/file"); // create regular file
fs::create_symlink("non-existing", "sandbox/symlink");
demo_exists("sandbox");
for (auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
demo_exists(*it, it->status()); // use cached status from directory entry
fs::remove_all("sandbox");
}
"sandbox" exists
"sandbox/file" exists
"sandbox/symlink" does not exist
create_directory 与 create_directories
show case
#include <cstdlib>
#include <experimental/filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::experimental::filesystem;
int main()
{
fs::create_directories("sandbox/1/2/a");//如果路径中的任何父目录不存在 一并创建。
fs::create_directory("sandbox/1/2/b");//前提是路径中的所有父目录已经存在
fs::permissions("sandbox/1/2/b", fs::perms::remove_perms | fs::perms::others_all);//移除其他用户的所有权限
fs::create_directory("sandbox/1/2/c", "sandbox/1/2/b");//以sandbox/1/2/b的属性创建目录sandbox/1/2/c
std::system("ls -l sandbox/1/2");//调用系统命令ls
fs::remove_all("sandbox");//递归地删除sandbox目录及其所有内容
}
drwxr-xr-x 2 user group 4096 Apr 15 09:33 a
drwxr-x--- 2 user group 4096 Apr 15 09:33 b
drwxr-x--- 2 user group 4096 Apr 15 09:33 c
directory_iterator 与 relative_path() 与 is_directory
#include <experimental/filesystem>
#include <fstream>
#include <iostream>
#include <typeinfo>
// g++ test.cc -o test -std=c++17 -lstdc++fs
namespace fs = std::experimental::filesystem;
int main()
{
// 1.测试directory_iterator
std::cout << "测试directory_iterator" << std::endl;
fs::create_directories("sandbox/a/b");
std::ofstream{"sandbox/file1.txt"};
std::ofstream{"sandbox/file2.txt"};
for (const fs::directory_entry &entry : fs::directory_iterator{"sandbox"})
std::cout << entry << '\n';
fs::remove_all("sandbox");
/*
"sandbox/a"
"sandbox/file2.txt"
"sandbox/file1.txt"
*/
std::cout << std::endl;
// 2.测试relative_path()
std::cout << "测试relative_path()" << std::endl;
fs::path curPath = fs::current_path();
std::cout << "The current path " << curPath << " decomposes into:\n"
<< "root-path " << curPath.root_path() << '\n'
<< "relative-path " << curPath.relative_path() << '\n';
/*
The current path "C:\Users\abcdef\Local Settings\temp" decomposes into:
root-path "C:\"
relative-path "Users\abcdef\Local Settings\temp"
*/
std::cout << std::endl;
// 3.测试is_directory
std::cout << "测试is_directory" << std::endl;
fs::path p = "./test1.txt";
fs::path p2 = "../server";
if (fs::is_directory(p))
std::cout << p << " is a directory." << std::endl;
else
std::cout << p << " is not a directory." << std::endl;
if (fs::is_directory(p2))
std::cout << p2 << " is a directory." << std::endl;
else
std::cout << p2 << " is not a directory." << std::endl;
return 0;
}
scandir<难用 不好用>
vim-Tips
vim底行模式输入set nonu可以关闭行号 便于复制
c语言库函数remove
2.整体代码
// 当文件增多 极有可能出现头文件重复包含 使用预处理指令
// 使得当该头文件已被包含时 不再重复包含该文件
#ifndef __MY_FILEUTIL__
#define __MY_FILEUTIL__
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <experimental/filesystem>
#include <sys/stat.h>
#include "./mylib/include/bundle.h"
#include "log.hpp"
// 同一个工程中允许存在多个相同名称的命名空间 最后合成同一个命名空间
namespace cloudBackup
{
// 简洁命名
namespace filesystem = std::experimental::filesystem;
class FileUtil
{
private:
std::string _filename;
public:
FileUtil(const std::string &filename)
: _filename(filename)
{
}
// 获取文件大小
int64_t FileSize()
{
struct stat statBuf;
// int stat(const char *file, stat *buf)
if (stat(_filename.c_str(), &statBuf) < 0)
{
Log::log(Error, "FileUtil::stat-get file size failed!: %s: %d", strerror(errno), errno);
return -1;
}
return statBuf.st_size;
}
// 由文件路径获取纯文件名称
std::string FileName()
{
// ./a/b/c/test.txt --> test.txt
size_t pos = _filename.find_last_of("/");
if (pos == std::string::npos) // 没找到/ 说明本就是不带路径的文件
return _filename;
return _filename.substr(pos + 1);
}
// 获取最后一次访问时间
time_t LastATime()
{
struct stat statBuf;
// int stat(const char *file, stat *buf)
if (stat(_filename.c_str(), &statBuf) < 0)
{
Log::log(Error, "FileUtil::stat-get last_atime failed!: %s: %d", strerror(errno), errno);
return -1;
}
return statBuf.st_atime;
}
// 获取最后一次状态改变时间
time_t LastCTime()
{
struct stat statBuf;
// int stat(const char *file, stat *buf)
if (stat(_filename.c_str(), &statBuf) < 0)
{
Log::log(Error, "FileUtil::stat-get last_ctime failed!: %s: %d", strerror(errno), errno);
return -1;
}
return statBuf.st_ctime;
}
// 获取最后一次修改时间
time_t LastMTime()
{
struct stat statBuf;
// int stat(const char *file, stat *buf)
if (stat(_filename.c_str(), &statBuf) < 0)
{
Log::log(Error, "FileUtil::stat-get last_mtime failed!: %s: %d", strerror(errno), errno);
return -1;
}
return statBuf.st_mtime;
}
// 获取文件pos后len长度的数据 传递给content
bool GetPosLen(std::string *content, size_t pos, size_t len)
{
// pos后文件长度不足len
size_t fsize = this->FileSize();
if (pos + len > fsize)
{
Log::log(Error, "FileUtil::GetPosLen pos + len > fsize !: %s: %d", strerror(errno), errno);
return false;
}
std::ifstream ifs;
ifs.open(_filename, std::ios::binary);
if (ifs.is_open() == false)
{
Log::log(Error, "FileUtil::GetPosLen::ifs.is_open() failed !: %s: %d", strerror(errno), errno);
return false;
}
ifs.seekg(pos, std::ios::beg);
content->resize(len);
// &(*content)[0] == &( (*content)[0] ) 这么做是因为read接收char*类型
ifs.read(&(*content)[0], len);
// 检查在读取文件内容的过程中是否发生了错误
if (ifs.good() == false)
{
Log::log(Error, "FileUtil::GetPosLen::ifs.good()-get file content failed !: %s: %d", strerror(errno), errno);
ifs.close();
return false;
}
ifs.close();
return true;
}
// 获取整个文件内容传递给content #代码复用
bool GetContent(std::string *content)
{
size_t fsize = this->FileSize();
return GetPosLen(content, 0, fsize);
}
// 将content中的数据写入到文件
bool SetContent(const std::string &content)
{
std::ofstream ofs;
ofs.open(_filename, std::ios::binary);
if (ofs.is_open() == false)
{
Log::log(Error, "FileUtil::SetContent::ofs.is_open()-open file failed !: %s: %d", strerror(errno), errno);
return false;
}
ofs.write(&content[0], content.size());
if (ofs.good() == false)
{
Log::log(Error, "FileUtil::SetContent::ofs.good()-write file content failed !: %s: %d", strerror(errno), errno);
ofs.close();
return false;
}
ofs.close();
return true;
}
// 将成员属性_filename中的数据压缩后存入zipFile
bool Compress(const std::string &zipFile)
{
// 1. 获取原文件内容存入到content binary->string
std::string content;
if (this->GetContent(&content) == false)
{
Log::log(Error, "FileUtil::Compress::GetContent()-get file content failed !: %s: %d", strerror(errno), errno);
return false;
}
// 2. 对数据进行压缩 string->string.zip
std::string packed = bundle::pack(bundle::LZIP, content);
// 3. 将压缩后的数据存储到压缩包文件中
FileUtil fileUtil(zipFile);
if (fileUtil.SetContent(packed) == false)
{
Log::log(Error, "FileUtil::Compress::SetContent()-write packed data failed !: %s: %d", strerror(errno), errno);
return false;
}
return true;
}
// 将成员属性_filename中的数据解压后存入zipFile
bool DeCompress(const std::string &unzipFile)
{
// 读取成员属性_filename压缩包数据存入content
std::string content;
if (this->GetContent(&content) == false)
{
Log::log(Error, "FileUtil::DeCompress::GetContent()-get file content failed !: %s: %d", strerror(errno), errno);
return false;
}
// 对压缩包数据进行解压缩
std::string unpacked = bundle::unpack(content);
// 将解压缩的数据写入到新文件unzipFile
FileUtil fileUtil(unzipFile);
if (fileUtil.SetContent(unpacked) == false)
{
Log::log(Error, "FileUtil::DeCompress::SetContent()-write unpacked data failed !: %s: %d", strerror(errno), errno);
return false;
}
return true;
}
// 判断文件是否存在
bool Exists(filesystem::file_status status = filesystem::file_status{})
{
// bool exists(const path& p);
if (filesystem::status_known(status) ? filesystem::exists(status) : filesystem::exists(_filename))
return true;
else
return false;
}
// 删除某个文件
bool Remove()
{
if (this->Exists() == false)
return true;
// int remove(const char *pathname);
remove(_filename.c_str());
return true;
}
// 创建目录 目录是一个可以包含文件的文件
bool CreateDirectory()
{
if (this->Exists())
return true;
// 路径中的任何父目录不存在 一并创建
return filesystem::create_directories(_filename);
}
// 浏览_filename这个 目录 下所有文件名 存入fileArray
bool ScanDirectory(std::vector<std::string> *fileArray)
{
// const fs::directory_entry &entry
for (const auto &entry : filesystem::directory_iterator(_filename))
{
//如果浏览到了目录 则跳过 (我们只需要获取文件)
if (filesystem::is_directory(entry) == true)
continue;
// relative_path 不带根路径的路径
fileArray->push_back(filesystem::path(entry).relative_path().string());
}
return true;
}
};
}
#endif //__MY_FILEUTIL__