Files
dl_old/dl/io/dl_file.cpp
T
2026-05-27 15:06:50 +08:00

1205 lines
25 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "io/dl_file.h"
#include <filesystem>
#include <regex>
#include <sstream>
#if DL_PLATFORM == DL_PLATFORM_WIN32
#include <Shlobj_core.h>
#endif
#include "io/dl_log.h"
#include "math/dl_algorithm.h"
#include "memory/dl_code_cvt.h"
#include "memory/dl_stream_input.h"
#include "memory/dl_stream_output.h"
#include "base/dl_string.h"
#include "system/dl_android.h"
#include "memory/dl_crypto.h"
#include "system/dl_engine.h"
#include "io/dl_json.h"
namespace dl::File
{
#if (DL_PLATFORM == DL_PLATFORM_ANDROID)
std::string_view CastU8StringView(std::string_view str)
{
return { str.data(), str.size() };
}
std::string ToString(std::u8string_view str)
{
return { (char*)str.data(), str.size() };
}
#else
std::u8string_view CastU8StringView(std::string_view str)
{
return { (char8_t*)str.data(), str.size() };
}
std::string ToString(std::u8string_view str)
{
return { (char*)str.data(), str.size() };
}
#endif
std::string_view CastStringView(std::u8string_view str)
{
return { (char*)str.data(), str.size() };
}
Buffer GetBuffer(std::ifstream& ifs)
{
Buffer ret;
ifs.seekg(0, std::ios::end);
ret.resize((size_t)ifs.tellg());
ifs.seekg(0, std::ios::beg);
ifs.read((char*)ret.data(), ret.size());
ifs.seekg(0, std::ios::beg);
return ret;
}
Buffer GetBuffer(std::string_view path_name)
{
std::ifstream ifs = Get(path_name, true);
if (!ifs.is_open())
{
log_err("文件打开失败: {}", path_name );
return {};
}
return GetBuffer(ifs);
}
//
//
//bool File::HashBlake2b(string_view path_name, Crypto::Blake2b& blake2b)
//{
// Buffer buf = GetBuffer(path_name);
// if (buf.Empty())
// return false;
//
// blake2b = Crypto::HashBlake2b(buf);
// buf.Delete();
//
// return true;
//}
//
//
//bool File::HashBlake2bCheck(string_view path_name, const Crypto::Blake2b& digest)
//{
// Buffer buf = GetBuffer(path_name);
// if (buf.Empty())
// return false;
//
// bool ret = Crypto::HashBlake2bCheck(buf, digest);
// buf.Delete();
//
// return ret;
//}
//
//
//uint32_t File::GetCrc32(string_view path_name)
//{
// Buffer buf = GetBuffer(path_name);
// if (buf.Empty())
// return 0;
//
// uint32_t ret = Crypto::HashCrc32(buf);
// buf.Delete();
// return ret;
//}
// 目录迭代器
inline std::filesystem::directory_iterator MakeDirectoryIterator(std::string_view path)
{
#if DL_PLATFORM == DL_PLATFORM_ANDROID
std::string str{path};
if(str.empty() || str[0] != '/')
{
str = PathCurrent() + str;
}
return std::filesystem::directory_iterator{ str };
#else
return std::filesystem::directory_iterator{ CastU8StringView(path) };
#endif
}
// 生成路径
inline std::filesystem::path MakePath(std::string_view path)
{
#if DL_PLATFORM == DL_PLATFORM_ANDROID
std::string str{path};
if(str.empty() || str[0] != '/')
{
str = PathCurrent() + str;
}
return std::filesystem::path{ str };
#else
return std::filesystem::path{ CastU8StringView(path) };
#endif
}
// 还原至安卓的相对路径
inline void RevertPath(std::string& path)
{
#if DL_PLATFORM == DL_PLATFORM_ANDROID
if(!Erase::HeadSub(path, PathCurrent()))
log_err("RevertPath 失败!");
#endif
}
void GetPathFileAll(std::string_view path, std::vector<std::string>& ret,
std::string_view regex, bool recursion)
{
using directory_iterator = std::filesystem::directory_iterator;
std::list<directory_iterator> vec_path;
try
{
directory_iterator path_iter = MakeDirectoryIterator(path);
vec_path.push_back(path_iter);
}
catch (std::filesystem::filesystem_error& e)
{
log_err0(e);
return;
}
bool no_reg = true;
std::regex reg;
if (!regex.empty())
{
try
{
reg = std::regex{ std::string{ regex }, std::regex::icase };
}
catch (std::regex_error& e)
{
log_err0(e);
return;
}
no_reg = false;
}
operate_front(vec_path, [&](const directory_iterator& iter_path)
{
for (auto& fe : iter_path)
{
if (fe.status().type() == std::filesystem::file_type::directory)
{
if(recursion)
vec_path.push_back(directory_iterator{ fe });
}
else
{
std::string path_name = fe.path().string();
String::CvtPathSeparator(path_name);
#if DL_PLATFORM == DL_PLATFORM_WIN32
path_name = dl::CodeCvt::MultiByteToUtf8(path_name.c_str());
#endif
if (no_reg || std::regex_search(path_name, reg))
{
RevertPath(path_name);
ret.push_back(path_name);
}
}
}
});
}
void GetPathFileAll(std::string_view path, std::vector<std::string>& ret, const SearchRule& rule, bool recursion)
{
using directory_iterator = std::filesystem::directory_iterator;
std::list<directory_iterator> vec_path;
try
{
directory_iterator path_iter = MakeDirectoryIterator(path);
vec_path.push_back(path_iter);
}
catch (std::filesystem::filesystem_error& e)
{
log_err0(e);
return;
}
operate_front(vec_path, [&](const directory_iterator& iter_path)
{
for (auto& fe : iter_path)
{
if (fe.status().type() == std::filesystem::file_type::directory)
{
if (recursion)
vec_path.push_back(directory_iterator{ fe });
}
else
{
std::string path_name = fe.path().string();
String::CvtPathSeparator(path_name);
#if DL_PLATFORM == DL_PLATFORM_WIN32
path_name = dl::CodeCvt::MultiByteToUtf8(path_name.c_str());
#endif
bool match = false;
for (auto& iter : rule._vecFmt)
{
if (Sub::IsTail(path_name, iter))
{
match = true;
break;
}
}
if (match)
{
for (auto& iter : rule._vecFilter)
{
if (Sub::IsTail(path_name, iter))
{
match = false;
break;
}
}
if (match)
{
RevertPath(path_name);
ret.push_back(path_name);
}
}
}
}
});
}
void GetPathContent(std::string_view path, std::vector<std::string>& ret,
std::string_view regex, bool folder, bool file)
{
using directory_iterator = std::filesystem::directory_iterator;
directory_iterator path_iter;
try
{
path_iter = MakeDirectoryIterator(path);
}
catch (std::filesystem::filesystem_error& e)
{
log_err0(e);
return;
}
bool no_reg = true;
std::regex reg;
if (!regex.empty())
{
reg = std::string{ regex };
no_reg = false;
}
for (auto& fe : path_iter)
{
if (fe.status().type() == std::filesystem::file_type::directory)
{
if (folder)
{
std::string path = fe.path().string();
String::CvtPathSeparator(path);
RevertPath(path);
#if DL_PLATFORM == DL_PLATFORM_WIN32
path = dl::CodeCvt::MultiByteToUtf8(path.c_str());
#endif
ret.push_back(path + "/");
}
}
else
{
if (file)
{
std::string path_name = fe.path().string();
String::CvtPathSeparator(path_name);
RevertPath(path_name);
#if DL_PLATFORM == DL_PLATFORM_WIN32
path_name = dl::CodeCvt::MultiByteToUtf8(path_name.c_str());
#endif
if (no_reg || std::regex_search(path_name, reg))
ret.push_back(path_name);
}
}
}
}
FILE* GetFile(std::string_view path_name, bool is_binary /*= true*/)
{
#if DL_PLATFORM == DL_PLATFORM_ANDROID
std::string str{ path_name };
if (str.empty() || str[0] != '/')
{
str = PathCurrent() + str;
}
#else
std::string str{ path_name };
#if DL_PLATFORM == DL_PLATFORM_WIN32
str = CodeCvt::Utf8ToMultiByte(str);
#endif
#endif
FILE* ret = fopen(str.c_str(), is_binary ? "rb" : "r");
return ret;
}
std::ifstream Get(std::string_view path_name, bool is_binary /*= true*/)
{
if(path_name.empty())
return {};
try
{
std::ifstream ret;
std::filesystem::path p = MakePath(path_name);
ret.open(p, is_binary ? (std::ifstream::binary | std::ifstream::in) : std::ifstream::in);
return ret;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return {};
}
std::ofstream Set(std::string_view path_name,
bool is_binary, bool is_app)
{
try
{
std::ofstream ret;
std::filesystem::path p = MakePath(path_name);
std::ofstream::openmode mode = std::ofstream::out;
if (is_binary)
mode |= std::ofstream::binary;
if (is_app)
mode |= std::ofstream::app;
else
mode |= std::ofstream::trunc;
ret.open(p, mode);
return ret;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return {};
}
bool ConvertMb2U8(std::string_view path_name, std::string_view out)
{
std::ifstream ifs = Get(path_name, false);
if (!ifs.is_open())
{
log_err("转换文件编码,文件加载失败:{}", path_name);
return false;
}
std::string str = GetString(path_name);
if (str.empty())
{
log_err("文件不存在,或为空:{}", path_name);
return false;
}
std::string str_u8 = CodeCvt::MultiByteToUtf8(str);
if (!SaveString(str_u8, out))
{
log_err("文件保存失败:{}", out );
return false;
}
return true;
}
time_t GetLastWriteTime(std::string_view path_name)
{
try
{
std::filesystem::path p = MakePath(path_name);
std::filesystem::file_time_type t = last_write_time(p);
std::chrono::file_clock::time_point tp = std::filesystem::file_time_type::clock::time_point(t);
std::chrono::nanoseconds dt = tp.time_since_epoch();
return (time_t)duration_cast<std::chrono::seconds>(dt).count();
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return 0;
// struct _stat64 fileInfo;
// std::string p = CodeCvt::Utf8ToMultiByte(path_name);
// if (_stat64(p.c_str(), &fileInfo) != 0)
// {
// log_err("获取文件信息失败: {}", path_name);
// }
// return fileInfo.st_mtime;
// return std::asctime(std::localtime(&cftime));
}
struct FileInfoCrc
{
std::string _pathName;
time_t _t;
uint32_t _crc32;
};
void to_json(json& j, const FileInfoCrc& info)
{
j = json{
{"path", info._pathName},
{"t", info._t},
{"crc", info._crc32}
};
}
void from_json(const json& j, FileInfoCrc& info)
{
j.at("path").get_to(info._pathName);
j.at("t").get_to(info._t);
j.at("crc").get_to(info._crc32);
}
bool CheckPathFileModified(std::string_view path_name, const SearchRule& rule, std::string_view cache, bool update)
{
log_info("尝试对文件夹进行改动检查:{},缓存文件:{}", path_name, cache);
constexpr uint32_t VERSION = 3;
if (!IsExist(cache))
{// cache文件不存在
// 按遍历加入即可
std::vector<FileInfoCrc> vec_file;
std::vector<std::string> mul_file;
GetPathFileAll(path_name, mul_file, rule);
// 遍历文件夹所有文件,记录{path_name, write_time}
for (auto& iter : mul_file)
{
uint32_t crc32 = GetCrc32(iter);
FileInfoCrc info;
info._crc32 = crc32;
info._pathName = iter;
info._t = GetLastWriteTime(iter);
vec_file.push_back(info);
}
//写入cache文件
json j;
j["version"] = VERSION;
j["files"] = vec_file;
File::SaveString(j.dump(4), cache);
}
else
{//cache文件存在
bool not_match = false;
do
{
json j = Json::ParseFile(cache);
if (j.is_null())
{
log_err("cache加载失败:{}", cache);
not_match = true;
break;
}
//
uint32_t version;
Json::Get(j, "version", version);
if (version != VERSION)
{
log_msg("VERSION值不匹配!");
not_match = true;
break;
}
std::vector<FileInfoCrc> vec_file;
Json::Get(j, "files", vec_file);
// 读取到cache文件数据后,再与现有文件比对
std::vector<std::string> mul_file;
GetPathFileAll(path_name, mul_file, rule);
// 数量不一致
if (vec_file.size() != mul_file.size())
{
log_msg("增加了文件:{} -> {}",
vec_file.size(), mul_file.size());
not_match = true;
}
else
{
auto iter = vec_file.begin();
//遍历文件夹所有文件
for (auto& iter_file : mul_file)
{
// 比较操作
time_t t = GetLastWriteTime(iter_file);
if (t != iter->_t)
{
log_msg("此文件时间戳变化:{},t:{} -> {}",
iter_file, iter->_t, t);
uint32_t crc32 = GetCrc32(iter_file);
if (crc32 != iter->_crc32
|| iter_file != iter->_pathName)
{
log_msg("此文件内容被修改:{},crc32:{} -> {}",
iter_file, iter->_crc32, crc32);
not_match = true;
break;
}
}
++iter;
}
}
} while (false);
if (not_match && update)
{
//删除
Delete(cache);
//再重建
if (CheckPathFileModified(path_name, rule, cache, false) == false)
log_err0("此处应该返回真。");
}
return not_match;
}
return true;
}
void DeleteContent(std::string_view path_name)
{
try
{
std::filesystem::path p = MakePath(path_name);
if (!exists(p))
return;
for (auto& de : std::filesystem::directory_iterator(p))
{
std::filesystem::remove_all(de.path());
}
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
}
std::string Search(std::string_view path, std::string_view file_name)
{
if (!File::IsExist(path))
return {};
using dir_iter = std::filesystem::directory_iterator;
std::list<dir_iter> vec_path;
try
{
dir_iter iter{ CastU8StringView(path) };
vec_path.push_back(iter);
}
catch (std::filesystem::filesystem_error& e)
{
log_err0(e);
return {};
}
std::string ret;
operate_front(vec_path, [&](const dir_iter& iter_path)
{
for (auto& fe : iter_path)
{
if (fe.status().type() == std::filesystem::file_type::directory)
{
vec_path.push_back(dir_iter{ fe });
}
else
{
std::string name = fe.path().filename().string();
if (name != file_name)
continue;
ret = fe.path().string();
String::CvtPathSeparator(ret);
#if DL_PLATFORM == DL_PLATFORM_WIN32
ret = dl::CodeCvt::MultiByteToUtf8(ret);
#endif
vec_path.clear();
}
}
});
return ret;
}
bool Copy(std::string_view source, std::string_view target,
CopyMode mode, bool recursion)
{
try
{
std::filesystem::path p0 = MakePath(source);
std::filesystem::path p1 = MakePath(target);
std::filesystem::copy_options option;
switch (mode)
{
case CopyMode::NONE:
option = std::filesystem::copy_options::none;
break;
case CopyMode::OVERRIDE:
option = std::filesystem::copy_options::overwrite_existing;
break;
case CopyMode::SKIP:
option = std::filesystem::copy_options::skip_existing;
break;
}
if (recursion)
option |= std::filesystem::copy_options::recursive;
std::error_code e;
copy(p0, p1, option, e);
if (e)
{
log_err0(to_string(e));
return false;
}
return true;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return false;
}
std::string GetExtension(std::string_view path_name, bool has_dot /*= false*/)
{
try
{
std::filesystem::path p = MakePath(path_name);
std::string ret = ToString(p.extension().u8string());
if (!has_dot && !ret.empty())
return std::string{ ret.begin() + 1, ret.end() };
return ret;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return {};
}
std::string GetFileName(std::string_view path_name)
{
try
{
std::filesystem::path p = MakePath(path_name);
return ToString(p.filename().u8string());
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return {};
}
std::string GetStem(std::string_view path_name)
{
try
{
std::filesystem::path p = MakePath(path_name);
return ToString(p.stem().u8string());
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return {};
}
bool CreateFolder(std::string_view path)
{
try
{
if (path.empty())
return false;
if (File::IsExist(path))
return true;
#if DL_PLATFORM == DL_PLATFORM_ANDROID
if (path[0] != '/')
{// 非绝对路径,则创建到Storage目录
std::filesystem::path p{ PathStorage() + path };
return create_directories(p);
}
#endif
if (path.back() == '/')
{// 末尾斜杠移除
std::string_view s{ path.begin(), path.end() - 1 };
std::filesystem::path p{ CastU8StringView(s) };
return create_directories(p);
}
std::filesystem::path p{ CastU8StringView(path) };
return create_directories(p);
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return false;
}
#if DL_PLATFORM == DL_PLATFORM_WIN32
struct FileImp
{
std::string _pathAppDataLocal;
std::string _pathAppDataLocalLow;
std::string _pathAppDataRoaming;
std::string _pathProgramData;
void Build()
{
{
wchar_t str[MAX_PATH] = {};
SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, str);
_pathAppDataLocal = CodeCvt::WideCharToUtf8(str);
String::CvtPathSeparator(_pathAppDataLocal);
_pathAppDataLocalLow = _pathAppDataLocal + "Low/";
_pathAppDataLocal += "/";
}
{
wchar_t str[MAX_PATH] = {};
SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, str);
_pathAppDataRoaming = CodeCvt::WideCharToUtf8(str);
String::CvtPathSeparator(_pathAppDataRoaming);
_pathAppDataRoaming += "/";
}
{
wchar_t str[MAX_PATH] = {};
SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, str);
_pathProgramData = CodeCvt::WideCharToUtf8(str);
String::CvtPathSeparator(_pathProgramData);
_pathProgramData += "/";
}
}
};
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
struct FileImp
{
std::string _pathFilesDir;
std::string _pathExternalFilesDir;
std::string _pathExternalStorageDirectory;
void Build()
{
}
};
#elif DL_PLATFORM == DL_PLATFORM_LINUX
struct FileImp
{
std::string _pathFilesDir;
std::string _pathExternalFilesDir;
std::string _pathExternalStorageDirectory;
void Build()
{
_pathFilesDir = "/home/lveyou/dltest/";
_pathExternalFilesDir = _pathFilesDir;
_pathExternalStorageDirectory = _pathFilesDir;
}
};
#endif
#if DL_PLATFORM == DL_PLATFORM_APPLE
struct FileImp
{
std::string _pathFilesDir;
std::string _pathExternalFilesDir;
std::string _pathExternalStorageDirectory;
void Build()
{
_pathFilesDir = "/Users/zego/code/dl/out/";
_pathExternalFilesDir = _pathFilesDir;
_pathExternalStorageDirectory = _pathFilesDir;
}
};
#endif
FileImp g_fileImp;
void InitFileSystem()
{
g_fileImp.Build();
File::CreateFolder(PathStorage());
File::CreateFolder(PathPrivate());
File::CreateFolder(PathPublic());
}
std::string PathCurrent()
{
#if DL_PLATFORM != DL_PLATFORM_ANDROID
// current_path 在安卓返回的是右斜杠
std::filesystem::path p = std::filesystem::current_path();
std::string ret = ToString(p.u8string());
ret += '/';
String::CvtPathSeparator(ret);
return ret;
#else
return PathStorage() + "assets/";
#endif
}
std::string PathTemp()
{
std::filesystem::path p = std::filesystem::temp_directory_path();
std::string ret = ToString(p.u8string());
String::CvtPathSeparator(ret);
return ret;
}
std::string PathStorage()
{
#if DL_PLATFORM == DL_PLATFORM_WIN32
return fmt::format("{}dl/{}/", g_fileImp._pathAppDataLocal, Engine::GetParamRef()._projectName);
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
return g_fileImp._pathExternalFilesDir;
#endif
}
std::string PathStorageRoot()
{
#if DL_PLATFORM == DL_PLATFORM_WIN32
return g_fileImp._pathAppDataLocal;
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
return PathPublic();
#endif
}
std::string PathPrivate()
{
#if DL_PLATFORM == DL_PLATFORM_WIN32
return fmt::format("{}dl/{}/", g_fileImp._pathAppDataLocal, Engine::GetParamRef()._projectName);
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
return g_fileImp._pathFilesDir;
#endif
}
std::string PathPublic()
{
#if DL_PLATFORM == DL_PLATFORM_WIN32
return fmt::format("{}dl/{}/", g_fileImp._pathProgramData, Engine::GetParamRef()._projectName);
#elif DL_PLATFORM == DL_PLATFORM_ANDROID
return g_fileImp._pathExternalStorageDirectory;
#endif
}
bool IsExist(std::string_view path_name)
{
if (path_name.empty())
{
return false;
}
try
{
std::filesystem::path p = MakePath(path_name);
return exists(p);
}
catch (std::filesystem::filesystem_error&)
{
}
catch (...)
{
}
return false;
}
bool Delete(std::string_view path_name, bool all /*= false*/)
{
try
{
std::filesystem::path p = MakePath(path_name);
return all ? remove_all(p) : remove(p);
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return false;
}
bool SaveBuffer(BufferView buf, std::string_view path_name)
{
std::ofstream ofs = Set(path_name, true);
if (!ofs.is_open())
return false;
ofs.write((char*)buf.data(), buf.size());
return true;
}
bool SaveString(BufferView buf, std::string_view path_name)
{
std::ofstream ofs = Set(path_name, false);
if (!ofs.is_open())
return false;
ofs.write((char*)buf.data(), buf.size());
return true;
}
bool SaveString(std::string_view str, std::string_view path_name)
{
return SaveString(CreateBufferView(str), path_name);
}
uint32_t GetCrc32(std::string_view path_name)
{
Buffer buf = GetBuffer(path_name);
if (buf.empty())
return 0;
return Crypto::HashCrc32(buf);
}
std::string GetString(std::string_view path_name)
{
std::ifstream ifs = Get(path_name, false);
if (!ifs.is_open())
{
return {};
}
std::stringstream buffer;
buffer << ifs.rdbuf();
return buffer.str();
}
std::string GetFolderName(std::string_view path_name)
{
std::string ret{ path_name };
if (Erase::TailFromLast(ret, '/'))
{
ret.pop_back();
return GetStem(ret);
}
return {};
}
std::string GetFilePath(std::string_view path_name)
{
if(path_name.empty())
return {};
std::string ret{ path_name };
if (ret.back() == '/')
return ret;
if (Erase::TailFromLast(ret, '/'))
{
return ret;
}
return {};
}
std::string GetAbsolute(std::string_view path_name)
{
try
{
std::filesystem::path p = MakePath(path_name);
std::string ret = std::filesystem::absolute(p).string();
#if DL_PLATFORM == DL_PLATFORM_WIN32
ret = dl::CodeCvt::MultiByteToUtf8(ret);
String::CvtPathSeparator(ret);
#endif
return ret;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return {};
}
std::string GetRelative(std::string_view path_name, std::string_view path_base)
{
try
{
std::filesystem::path p = MakePath(path_name);
std::filesystem::path p_base = MakePath(path_base);
std::string ret = std::filesystem::relative(p, p_base).string();
#if DL_PLATFORM == DL_PLATFORM_WIN32
ret = dl::CodeCvt::MultiByteToUtf8(ret);
String::CvtPathSeparator(ret);
#endif
return ret;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return {};
}
bool Rename(std::string_view src, std::string_view tar)
{
try
{
std::filesystem::path p_src = MakePath(src);
std::filesystem::path p_tar = MakePath(tar);
std::filesystem::rename(p_src, p_tar);
return true;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return false;
}
std::string GetParentPath(std::string_view path_name)
{
try
{
std::string str_path{ path_name };
if (!str_path.empty() && str_path.back() == '/')
str_path.pop_back();
std::filesystem::path p = MakePath(path_name);
str_path = ToString(p.parent_path().u8string());
if (!str_path.empty() && str_path.back() != '/')
str_path += '/';
return str_path;
}
catch (std::filesystem::filesystem_error& e)
{
log_err("{}", e.what());
}
catch (...)
{
log_err("未知异常!");
}
return std::string{ path_name };
}
std::vector<std::string> PathRegular()
{
std::vector<std::string> ret;
#if DL_PLATFORM == DL_PLATFORM_WIN32
// 1. 获取盘符位掩码
DWORD drive_mask = GetLogicalDrives();
if (drive_mask == 0)
{ // 获取失败
DWORD error_code = GetLastError();
log_warn("获取盘符失败!错误码:{}", error_code);
}
else
{
// 2. 遍历 A-Z 盘符(共26个)
for (char drive = 'A'; drive <= 'Z'; ++drive)
{
// 计算当前盘符对应的位掩码
DWORD bit = 1 << (drive - 'A');
// 判断该位是否为1(盘符存在)
if (drive_mask & bit)
{
std::string drive_path = std::string(1, drive) + ":/";
ret.push_back(drive_path);
}
}
}
#endif
return ret;
}
}
#if DL_PLATFORM == DL_PLATFORM_ANDROID
std::string Android_JstringToString(JNIEnv *env, jstring j_str)
{
const char *cstr = env->GetStringUTFChars(j_str, NULL);
std::string ret = std::string(cstr);
env->ReleaseStringUTFChars(j_str, cstr);
return ret;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_dl_project_MainActivity_SetStoragePath(JNIEnv *env, jobject thiz,
jstring str_private,
jstring str_storage,
jstring str_public)
{
dl::File::g_fileImp._pathFilesDir = Android_JstringToString(env, str_private);
dl::File::g_fileImp._pathExternalFilesDir = Android_JstringToString(env, str_storage);
dl::File::g_fileImp._pathExternalStorageDirectory = Android_JstringToString(env, str_public);
dl::File::g_fileImp._pathFilesDir += "/";
dl::File::g_fileImp._pathExternalFilesDir += "/";
dl::File::g_fileImp._pathExternalStorageDirectory += "/";
}
#endif