读取文件夹进行内视频用于截图操作时,碰到了以下问题。源代码如下,帮忙看下。
显示错误 无法识别文件夹Error: Directory does not exist or is not a directory.

#include <iostream>
#include <filesystem>
#include <fstream>
#include <vector>
#include <string>
#include <set>
#include <chrono>
//#include <thread>
#include <cstdlib> // for std::system
#include <algorithm>
#include "mingw.thread.h"
namespace fs = std::filesystem; //用fs简写代表std::filesystem 提供对文件系统的操作 目录遍历,创建,删除等
/**
* @brief 判断给定文件路径是否为 IPC 文件
*
* 该函数检查文件路径的扩展名是否为 ".ipc",如果是,则返回 true,表示该文件是一个 IPC 文件;否则返回 false。
*
* @param filePath 文件路径
* @return true 如果文件路径的扩展名为 ".ipc"
* @return false 如果文件路径的扩展名不是 ".ipc"
*/
bool isIPCFile(const fs::path &filePath) //定义函数isIPCFile,接受一个检查的文件系统中的路径filePath参数名称,文件路径
{
return filePath.extension() == ".mp4";
//extension为获取文件的扩展名,如果文件路径的扩展名为".ipc",返回true,否则返回false
}
/**
* @brief 从视频文件中截取屏幕截图并保存到指定目录
*
* @param videoPath 视频文件的路径
* @param outputdir 截图保存的输出目录
* @return void 如果截图过程中发生错误,将在标准错误流中输出错误信息
*
* 使用ffmpeg命令行工具,以每0.2秒截取一帧的速度从视频中截取屏幕截图,
* 并将截图保存为PNG格式的文件,文件名格式为image0001.png, image0002.png等。
* 如果ffmpeg命令执行失败(返回值不为0),则输出错误信息。
*/
void takeScreenshots(const fs::path &videoPath, const fs::path &outputdir)
//定义函数takeScreenshots,接收两个文件系统的路径,videoPath为视频文件的路径,outputdir为截图保存的输出目录
{
std::string command = "ffmpeg -i \"" + videoPath.string() + "\" -vf fps=1/0.2 " + outputdir.string() + "/image%04d.png";
//定义一个字符串变量command,用于存储构建的命令行
//执行ffmpeg命令,以每0.2秒截取一帧的速度从视频中截取屏幕截图,并将截图保存为PNG格式的文件,文件名格式为image0001.png, image0002.png等。
int result = std::system(command.c_str());
//std::system执行一个系统命令,接受一个字符串参数
//command.c_str()是一个成员函数调用,指向字符数组
//定义一个变量result,用于存储ffmpeg命令执行的结果,表示命令执行的状态
if (result != 0){
std::cerr << "Error taking screenshots for" << videoPath << '\n'; //不为0则输出错误信息
}
}
/**
* @brief 查找指定目录及其子目录下的IPC文件,并将找到的文件路径存储到向量中。
*
* @param directoryPath 要搜索的目录路径。
* @param foundFiles 一个集合,用于存储已经找到的文件路径,以避免重复添加。
* @return std::vector<fs::path> 包含找到的IPC文件路径的向量。
*
* 该函数首先检查指定的目录是否存在且为一个目录。然后,递归地遍历该目录及其所有子目录,
* 对于每个常规文件,如果其扩展名为".ipc"且未被添加到foundFiles集合中,则将其路径添加到ipcFiles向量中,
* 并标记为已找到。最后返回包含所有找到的IPC文件路径的向量。
*/
std::vector<fs::path> findIPCFiles(const fs::path &directoryPath, std::set<fs::path> &foundFiles)
//返回一个std::vector容器,用于存储找到的IPC文件路径
//定义函数findIPCFiles,接受两个参数,directoryPath为要搜索的目录路径,foundFiles为一个集合,用于存储已经找到的文件路径,以避免重复添加
{
std::vector<fs::path> ipcFiles; // 声明一个名为ipcFiles的向量,用于存储找到的IPC文件路径
if (!fs::exists(directoryPath) || !fs::is_directory(directoryPath)){// 判断指定的目录是否存在且是一个目录
std::cerr<<"Error: Directory does not exist or is not a directory.\n"; //不存在则error
return ipcFiles; //返回向量空路径
}
//对于directoryPath指定的目录及其所有子目录中的每一个文件和目录项,执行循环体内的代码。
//整个循环会遍历 directoryPath 指定的目录及其所有子目录中的文件和目录项。使用 entry 来访问当前遍历到的目录项的信息,例如它的路径、文件名等。
for (const auto &entry : fs::recursive_directory_iterator(directoryPath)){
//entry指代fs::recursive_directory_iterator迭代器返回的每一个目录项
if (fs::is_regular_file(entry.status()) && isIPCFile(entry.path()) && foundFiles.find(entry.path()) == foundFiles.end()) {
//如果entry指向的文件是一个常规文件,且扩展名为".ipc",且该文件未被添加到foundFiles集合中,则将文件路径添加到ipcFiles向量中,并标记为已找到
ipcFiles.push_back(entry.path());//将entry指向的文件路径添加到ipcFiles向量vector的末尾
foundFiles.insert(entry.path()); //标记该文件为已找到
//将找到的文件路径添加到两个容器中去
}
}
return ipcFiles;
}
/**
* @brief 删除指定目录下旧的截图文件夹
*
* 该函数会遍历指定目录下的所有子目录,并根据最后修改时间进行排序。
* 然后删除除了最新的keepCount个目录之外的所有目录。
*
* @param baseDir 需要处理的目录路径
* @param keepCount 需要保留的最新目录数量,默认为2
*/
void deleteOldScreenshotDirectories(const fs::path &baseDir, int keepCount = 2)
{ // 定义函数deleteoldScreenshotDirectories
std::vector<fs::directory_entry> dirs; // 创建一个vector容器,用于存储baseDir目录下的所有子目录
for (const auto &entry : fs::directory_iterator(baseDir))
{ // 遍历baseDir目录下的所有子目录
if (fs::is_directory(entry.status()))
{ // 如果entry指向的文件是一个目录
dirs.push_back(entry); // 将entry指向的文件路径添加到dirs容器中
}
}
std::sort(dirs.begin(), dirs.end(), [](const fs::directory_entry &a, const fs::directory_entry &b) { // 对dirs容器中的所有目录进行排序
return fs::last_write_time(a) > fs::last_write_time(b); // 按照最后修改时间进行排序
});
for (size_t i = 0; i < dirs.size() - keepCount; ++i)
{ // 删除dirs容器中最后keepCount个目录
fs::remove_all(dirs[i].path()); // 删除dirs容器中第i个目录
}
}
/**
* @file main.cpp
* @brief 主程序入口,负责搜索指定目录下的IPC文件,并对每个文件进行截图处理。
* @details 本程序会无限循环检查指定目录下的IPC文件,对每个找到的文件创建一个目录用于保存截图,
* 然后调用截图函数进行处理。同时,程序会定期删除旧的截图目录以避免空间占用过多。
* @author [你的名字]
* @version 1.0
* @date [日期]
* @copyright 版权所有 (C) [年份] [你的名字或公司名]
* @warning 本程序设计为无限循环运行,请确保在适当的时候手动停止。
*/
int main()
{
// 搜索指定目录下的IPC文件
fs::path directoryPath = "D:/tVideo"; // 使用directoryPath为实际的目录路径
fs::path baseScreenshotDir = "D:/tScreenshots"; // 使用baseScreenshotDir为实际的截图目录路径
std::set<fs::path> foundFiles; // 用于存储已经找到的文件路径,以避免重复添加
// 确保截图目录存在
if (!fs::exists(baseScreenshotDir)) {
fs::create_directories(baseScreenshotDir);
}
while (true) { // 用于无限循环检查并处理
// 查找IPC文件
std::vector<fs::path> ipcFiles = findIPCFiles(directoryPath, foundFiles);
// 用于处理找到的IPC文件
for (const auto& ipcFile : ipcFiles) {//循环ipcFiles向量中的每一个文件
//创建一个目录用于保存截图
fs::path videoName = ipcFile.stem(); // 获取视频名称
fs::path outputDir = baseScreenshotDir / videoName.string();//用于保存截图的目录
fs::create_directories(outputDir);//用于保存截图的目录
// 用于截取截图
takeScreenshots(ipcFile, outputDir);
}
// 删除旧的截图目录
deleteOldScreenshotDirectories(baseScreenshotDir);
// 睡眠一段时间,然后再次检查
std::this_thread::sleep_for(std::chrono::hours(1)); // 确保程序不会占用过多资源
}
return 0;
}