专业编程基础技术教程

网站首页 > 基础教程 正文

一个操作文件系统C++类模板实现(操作系统定义一个文件名由什么和什么组成)

ccvgpt 2024-08-03 12:31:32 基础教程 15 ℃
不废话,直接说特点。
特点:
1、利用C++类模板,实现 .h 头文件和 .cpp 代码实现文件的分离。
对于一些软件工程师,平时既想使用C++模板,又想隐藏源代码的情况,具有参考意义。
2、确保完全独立创新、可用、可测。事实上本人对于发布的源代码均编写了对应的单元测试代码。
并且代码的覆盖率超过90%。
3、同时支持 ANSI 和 UNICODE 版本。
4、高效、干净、安全。没有多余的废代码。

在当下,还潜心专注C/C++开发的人,应该为数不多吧。
如果有兴趣的同学,若在使用过程中有任何问题,欢迎交流!
.h 头文件
/**
* @file 文件名
* @brief 文件概要信息描述
* @author 作者
* @version 版本
* @date 日期
*
* @copyright 版权信息
*
* @par 修改日志:
* <table>
* <tr><th>Date	 <th>Version  <th>Author  <th>Description
* <tr><td>日期 	<td>版本     <td>作者      <td>说明
* </table>
*/
#pragma once
#include "bsbase\bs.h"
#include "bsbase\bsconst.h"
#include "bsbase\bsbase.h"
#include "bsbase\bsnoncopyable.h"
#include "bsbase\bsfunT.h"
DECLARE_NS_BSC
using namespace std;
//////////////////////////////////////////////////////////////////////////

enum { eFS_DISK = 0, eFS_DIR, eFS_FILENAME, eFS_EXT };

template <typename T = enable_if_t<is_base_of_v<basic_string<typename T::value_type>, T> > >
class BASE_API CBsFS final : private noncopyable
{
public:
	typedef typename T::value_type _type;
	typedef basic_string<_type> _Base;
	typedef const _type _ctype;

private:
	CBsFS(void);
	virtual ~CBsFS(void);

public:	
	/**
	* @brief Split file path into several parts
	* @param[in]  strFileFrom: Pointer to a null-terminated string that specifies the name of an existing file.
	* @param[in]  strFileTo: Pointer to a null-terminated string that specifies the name of the new file.
	* @param[out] oMap: The splited path filled in the map
	* @return BOOL
	* @retval TRUE: If the function succeeds.
	* @retval FALSE: If the function fails and the size of oMap is equal to zero.
	 @note	
		e.g.
		@code
		tstring strFilePath = _T("C:\\abc\\def");
		map<int, tstring> oMap;
		BS::CBsFS<tstring>::SplitPath(strFilePath, oMap);
		map<int, string> oMap1;
		BS::CBsFS<string>::SplitPath(string("D:\\qwe\\rty"), oMap1);		
		@endcode
		"C:\\abc\\def.txt" => map[eFS_DISK]="C:" map[eFS_DIR]="\\abc\\" map[eFS_FILENAME]="def" map[eFS_EXT]=".txt"
	*/
	static  BOOL SplitPath(const T& strFilePath, map<int, T>& oMap) _NOEXCEPT;

	/**
	* @brief Make file path according to several parts, it is the reverse of SplitPath function
	* @param[in]  oMap: The map the include file path
	* @return tstring/bsastring
	* @retval tstring/bsastring: File path that composed

	e.g. map[eFS_DISK]="C:" map[eFS_DIR]="\abc\" map[eFS_FILENAME]="def" map[eFS_EXT]=".txt" => "C:\abc\def.txt"
	*/
	static T MakePath(const map<int, T>& oMap) _NOEXCEPT;

	/**
	* @brief Get file directory according to file path
	* @param[in]  strFilePath: The file path
	* @return tstring/bsastring
	* @retval empty string: If input file path is empty, or doesn't include '/' or '\\', then return empty string
	* @retval tstring/bsastring: File directory including '\\',

	e.g. "C:\\abc\\def.txt" => "C:\\abc\\"
	*/
	static T GetFileDir(const T& strFilePath) _NOEXCEPT;
	//"C:\\abc\\def.txt" => "def.txt"
	static T GetFileName(const T& strFilePath) _NOEXCEPT;
	//C:\\abc\\def.txt" => ".txt" "def.txt" => ".txt"  "\\def.txt" => ".txt"  "//def.txt" => ".txt"
	static T GetFileExt(const T& strFName, BOOL tfLower = FALSE) _NOEXCEPT;
	//"C:\abc\def => C:\abc\" "C:\abc\def\ => C:\abc\"
	static T GetParentDir(const T& strDir) _NOEXCEPT;

	static BOOL IsExists(const T& strFilePath); //apply to file & directory
	//"C:" + "def" => "C:\\def" "C:\\abc" + "def" => "C:\\abc\\def"
	//"C:\\def" + "\\" => "C:\\def\\"
	static T PathAppend(const T& strPath, const T& strAppend, _ctype chSep = _ctype(BS_SLASH_CHAR_A)) _NOEXCEPT;
	//"E:\\k\\xxx\\xxx\\" + "abc\\TestComposeFilePath\\" => "E:\\k\\xxx\\xxx\\abc\\TestComposeFilePath\\"
	static T ComposeFilePath(HMODULE hModule, const T& strFileName);

	static BOOL GetFileCreateTime(const T& strFilePath, FILETIME& refTime);
	static int64_t GetFileSize(const T& strFilePath);
	static int64_t GetFileSize(ifstream& ifs);
	static int64_t GetFileSize(ofstream& ofs);

	//SystemTime = UTC, LocalTime = current local time
	static void FileTimeToSystemTime(FILETIME& refTime, SYSTEMTIME& refSystemTime);	
	//"E:\\k\\xxx\\xxx\\xxx\\xxx\\xxx.exe"
	static T GetModuleFile(HMODULE hModule, HANDLE hProcess = nullptr);	
	//return directory with end of backslash('\'), e.g. "E:\\k\\xxx\\xxx\\debug\\"
	static T GetModuleFileDir(HMODULE hModule);
	// "xxx.exe"
	static T GetModuleFileName(HMODULE hModule, HANDLE hProcess = nullptr);

	static T ParentPath(const T& strFilePath);

	//default format is E_GUID_FORMAT_NULL(0)
	static T GenGUIDFileName(const UINT eFmt = 0);
	//"C:\\Users\\JACK~1\\AppData\\Local\\Temp\\"
	static T GetTemporaryFolder(void) _NOEXCEPT;
	//"C:\\Users\\JACK~1\\AppData\\Local\\Temp\\~bs489B.tmp"
	static T GetTempFileName(const T& strPrefix = T(), const UINT uUnique = 0) _NOEXCEPT;
	//"C:\\aaa\\efc.txt" + "bsfile" => "C:\\aaa\\efc.bsfile", only string replace, doesn't related to rename file name
	static T ChangeFileExt(const T& strFile, const T& strTargetExt) _NOEXCEPT;

	static T GetSpecificFolder(const UINT32 uFolderID);

	//e.g. "C:\\Program Files (x86)\\Brand\\nginx-rtmp-win32\\", the path must real existing path,
	//otherwise it will be 3 error code, means "The system cannot find the path specified."
	static T GetShortPathName(const T& strFilePath) _NOEXCEPT;

	//e.g. "C:\\Users\\xxx\\AppData\\Local"
	static T GetUserAppDataFolder(void) _NOEXCEPT;

	//e.g. "C:\\ProgramData"
	static T GetProgramDataFolder(void) _NOEXCEPT;

	//e.g. "C:\\Program Files (x86)"
	static T GetProgramFilesFolder(void) _NOEXCEPT;
	/**
	* @brief  Given the file path and delete it
	* @param[in]  pszPath       Pointer to a null-terminated string that specifies the file to be deleted
	* @param[out] 输出参数       输出参数描述信息
	* @return BOOL
	* @retval nonezero	If the function succeeds, the return value is nonzero.
			  zero		If the function fails, To get extended error information, call GetLastError
	*/
	static BOOL DeleteFile(_ctype* pszPath);
	static BOOL DeleteFile(const T& strPath);
	static void DeleteFiles(vector<T>& ovtFiles);
	/**
	* @brief  The CopyFile function copies an existing file to a new file. The CopyFileEx function provides 
	*		  two additional capabilities. CopyFileEx can call a specified callback function each time 
	*		  a portion of the copy operation is completed, and CopyFileEx can be canceled during the copy operation.
	* @param[in]  strFileFrom     Pointer to a null-terminated string that specifies the name of an existing file.
	* @param[in]  strFileTo       Pointer to a null-terminated string that specifies the name of the new file. 
	* @param[out] 输出参数       输出参数描述信息
	* @return BOOL
	* @retval nonezero	If the function succeeds, the return value is nonzero.
				zero		If the function fails, To get extended error information, call GetLastError
	*/
	static BOOL CopyFile(const T& strFileFrom, const T& strFileTo, const uint64_t ui64Max = ULLONG_MAX);
	//e.g. "E:\\k\\xxx\\xxx\\" => "E:\\k\\xxx\\xxx\\CopiedFiles", not include sub folders and its files
	static BOOL CopyFiles(const T& strFileFrom, const T& strFileTo, const uint64_t ui64Max = ULLONG_MAX);
	//e.g. "E:\\k\\xxx\\xxx\\*" => Folder Name Vector([0]="Folderxxx",[1]="UnitTestFolder0",[2]="UnitTestFolder1",...)
	//e.g. "E:\\k\\xxx\\xxx\\UnitTestFolder*" => Folder Name Vector([0]="UnitTestFolder0",[1]="UnitTestFolder1",[2]="UnitTestFolder1",...)
	static BOOL ListSubDirectory(const T& strFolder, vector<T>& vtFolders, const UINT32 uMax = UINT_MAX);
	//e.g. "E:\\k\\xxx\\xxx\\*" => File Name Vector
	//e.g. "E:\\k\\xxx\\xxx\\test_bsbase.*" => File Name Vector
	static BOOL ListSubFiles(const T& strFolder, vector<T>& vtFiles, const UINT32 uMax = UINT_MAX);
	static BOOL ListSubFiles(const T& strFolder, const T& strFilter, vector<T>& vtFiles, const UINT32 uMax = UINT_MAX);

	//"E:\\k\\xxx\\xxx\\CopiedFiles", Empty folder is not required, that is to say, Empty folder is not mandatory
	static BOOL DeleteFolder(const T& strFolder);
	static BOOL	TryToDeleteFile(const T& strFilename, const DWORD dwInterval /* ms */, const DWORD dwDuration /* ms */);
	static BOOL RecursiveCreateFolder(const T& strFolder, const UINT32 uFrom = 0);	

	/**
	* @brief  函数功能概要信息
	* @param[in]  输入参数       输入参数描述信息
	* @param[out] 输出参数       输出参数描述信息
	* @return 返回类型
	* @retval 返回值	返回值意义描述信息
	*/
	static BOOL BrowseDirectory(const T& strFileName);
	static BOOL LaunchBrowser(const T& sExeFileName, const T& strURL);
	/*
	LaunchBat("batfilepath param")
	e.g. LaunchBat(tstring(_T("E:\\k\\bscom\\output\\bin\\debug\\chrome105\\move.bat E:\\objs")));
	*/
	static BOOL LaunchBat(const T& strBatFile);
	static BOOL ReadLine(basic_ifstream<_type, char_traits<_type> >& ifs, T& strLine);
	static BOOL ReadLines(const T& strFilePath, vector<T>& vtLines);
	static T MkUniFileName(const DWORD dwCount = 0u, const T& strFileExt = T());
};

typedef CBsFS<tstring> wfs;
typedef CBsFS<bsastring> afs;

#if defined UNICODE || defined _UNICODE
#define fs wfs
#else
#define fs afs
#endif // !UNICODE && !_UNICODE

END_NS

#include "stdafx.h"
#include <type_traits>
#include <Psapi.h>
#include <ShlObj.h>
#include <atlcomcli.h>
#include <combaseapi.h>
#include "bsbase/bsfs.h"
#include "bsbase/bsos.h"
#include "bsbase/bsguid.h"
#include "bsbase/bstring.h"

cpp实现文件:
DECLARE_NS_BSC

static const DWORD MAX_NUMBER_FOLDERS = 100u;
static const DWORD MAX_NUMBER_FILES = 1000u;
static const DWORD MAX_FILE_SIZE = 157286400u; //150M = 150*1024*1024 = 157286400

INSTANCE_TEMPLATE_CLASS_1st(CBsFS, tstring);
INSTANCE_TEMPLATE_CLASS_1st(CBsFS, bsastring);

//////////////////////////////////////////////////////////////////////////
template <typename T>
CBsFS<typename T>::CBsFS(void) {

}

template <typename T>
CBsFS<typename T>::~CBsFS(void) {

}

template <typename T>
BOOL CBsFS<typename T>::SplitPath(const T& strFilePath, map<int, T>& oMap) _NOEXCEPT {
	if (strFilePath.empty())
		return FALSE;
	//if (is_base_of<TCHAR, _type>::value)
	//if (is_same_v<T::value_type, TCHAR>::value)
	//if (is_same<T::value_type, TCHAR>::value)
	//if (constexpr(sizeof(_type) == 2))
	//if (string(typeid(typename T::value_type _type).name()) == "unsigned short")	
	_type szDrive[_MAX_DRIVE] = {0}, szDir[_MAX_DIR] = {0}, szFName[_MAX_FNAME] = {0}, szExt[_MAX_EXT] = {0};
	bsplitpath_s(strFilePath.c_str(), szDrive, BsNumElms(szDrive), szDir, BsNumElms(szDir), 
		szFName, BsNumElms(szFName), szExt, BsNumElms(szExt));
	oMap.clear();
	oMap.insert(make_pair(eFS_DISK, szDrive));
	oMap.insert(make_pair(eFS_DIR, szDir));
	oMap.insert(make_pair(eFS_FILENAME, szFName));
	oMap.insert(make_pair(eFS_EXT, szExt));
	return (0 < oMap.size());
}

template <typename T>
T CBsFS<typename T>::MakePath(const map<int, T>& oMap) _NOEXCEPT {
	basic_ostringstream<_type, char_traits<_type>, allocator<_type> > ostm;
	for each (auto& var in oMap)
		ostm << var.second;
	return move(ostm.str());
}

template <typename T>
T CBsFS<typename T>::GetFileDir(const T& strFilePath) _NOEXCEPT {
	if (strFilePath.empty())
		return {};
	bsc::bstringT<_type> strPath(strFilePath.c_str());
	strPath.Replace(_type(BS_BACKSLASH_CHAR_A), _type(BS_SLASH_CHAR_A));
	T::size_type pos = strPath.rfind(_type(BS_SLASH_CHAR_A));
	if (pos == T::npos)
		return {};
	return move(strPath.substr(0, pos + 1));
}

template <typename T>
T CBsFS<typename T>::GetFileName(const T& strFilePath) _NOEXCEPT {
	if (strFilePath.empty())
		return {};
	bsc::bstringT<_type> strPath(strFilePath.c_str());
	strPath.Replace(_type(BS_BACKSLASH_CHAR_A), _type(BS_SLASH_CHAR_A));
	T::size_type pos = strPath.rfind(_type(BS_SLASH_CHAR_A));
	if (pos == T::npos)
		return {};
	return move(strPath.substr(pos + 1));
}

template <typename T>
T CBsFS<typename T>::GetFileExt(const T& strFName, BOOL tfLower/* = FALSE*/) _NOEXCEPT {
	T strExt = {};
	if (strFName.empty())
		return move(strExt);
	bsc::bstringT<_type> strFileName(strFName.c_str());
	strFileName.Replace(_type(BS_BACKSLASH_CHAR_A), _type(BS_SLASH_CHAR_A));
	T::size_type poslash = strFileName.find_last_of(_type(BS_SLASH_CHAR_A));
	if (T::npos != poslash)	{
		T::size_type pos = strFileName.find_last_of(_type(BS_DOT_CHAR_A));
		if (T::npos != pos && poslash < pos)
			strExt.assign(strFileName, pos, strFileName.size() - pos);
	}
	else
	{
		T::size_type pos = strFileName.find_last_of(_type(BS_DOT_CHAR_A));
		if (T::npos != pos)
			strExt.assign(strFileName, pos, strFileName.size() - pos);
	}
	if (tfLower && !strExt.empty()) // make lowercase
		transform(strExt.begin(), strExt.end(), strExt.begin(), ::tolower);
	return move(strExt);
}

template <typename T>
T CBsFS<typename T>::GetParentDir(const T& strDir) _NOEXCEPT {
	T strResult = {};
	if (strDir.empty())
		return move(strResult);
	bsc::bstringT<_type> strDirectory(strDir.c_str());
	strDirectory.Replace(_type(BS_BACKSLASH_CHAR_A), _type(BS_SLASH_CHAR_A));
	if (_type(BS_SLASH_CHAR_A) == strDirectory.at(strDirectory.length() - 1))
		strDirectory = strDirectory.substr(0, strDirectory.length() - 1);
	T::size_type poslash = strDirectory.find_last_of(_type(BS_SLASH_CHAR_A));
	if (T::npos != poslash)
		strResult.assign(strDirectory, 0, poslash + 1);
	return move(strResult);
}

template <typename T>
BOOL CBsFS<typename T>::IsExists(const T& strFilePath) { //apply to file & directory
	return (0 == BsGetFileStatus(strFilePath.c_str()));
}

template <typename T>
T CBsFS<typename T>::PathAppend(const T& strPath, const T& strAppend, _ctype chSep /*= _ctype(BS_SLASH_CHAR_A)*/) _NOEXCEPT {
	T strResult(strPath);
	if (!strResult.empty())	{
		if (strResult.at(strResult.size() - 1) != chSep)
			strResult += chSep;
	}
	//const T s = (strResult + strAppend);
	//return s;

	if (1u == strAppend.length()) {
		const _type c = strAppend.at(0);
		if (_type(BS_BACKSLASH_CHAR_A) == strAppend.at(0) || _type(BS_SLASH_CHAR_A) == strAppend.at(0))
			return move(strResult);
	}
	return move(strResult + strAppend);
	// If we use move(...) return value, and move(...) has param, e.g. strAppend
	// Then we should combination two strings in temp var, finally use move(...) to return value
	// otherwise, it will lead to memory repeated release issue.
	// Note: already find the root cause:release version linker to debug msvcrtd.lib, so change to linker to msvcrt.lib will be ok.
	// So rollback and keep original return move(strResult + strAppend);
}

template <typename T>
T CBsFS<typename T>::ComposeFilePath(HMODULE hModule, const T& strFileName) {
	if (strFileName.empty())
		return{};
	const T strDir = GetModuleFileDir(hModule);
	bsc::bstringT<_type> strFile(strFileName.c_str());
	strFile.Replace(_type(BS_BACKSLASH_CHAR_A), _type(BS_SLASH_CHAR_A));
	if (strFile.at(0) == _type(BS_SLASH_CHAR_A))
		strFile = strFile.substr(1);
	return move(strDir + strFile);
}

template <typename T>
BOOL CBsFS<typename T>::GetFileCreateTime(const T& strFilePath, FILETIME& refTime) {
	return BsGetFileCreateTime(strFilePath.c_str(), refTime);
}

template <typename T>
int64_t CBsFS<typename T>::GetFileSize(const T& strFilePath) {
	return BsGetFileSize(strFilePath.c_str());
}

template <typename T>
int64_t CBsFS<typename T>::GetFileSize(ifstream& ifs) {
	if (!ifs.is_open())
		return -1;
	ifstream::pos_type pos = ifs.tellg();
	ifs.seekg(0, ios::end);
	ifstream::pos_type end = ifs.tellg();
	ifs.seekg(pos, ios::beg);
	return (end - pos);
}

template <typename T>
int64_t CBsFS<typename T>::GetFileSize(ofstream& ofs) {
	if (!ofs.is_open())
		return -1;
	ofstream::pos_type pos = ofs.tellp();
	ofs.seekp(0, ios::end);
	ofstream::pos_type end = ofs.tellp();
	ofs.seekp(pos, ios::beg);
	return (end - pos);
}

template <typename T>
void CBsFS<typename T>::FileTimeToSystemTime(FILETIME& refTime, SYSTEMTIME& refSystemTime) {
	FILETIME ftLocalTime = {0};
	FileTimeToLocalFileTime(&refTime, &ftLocalTime);
	::FileTimeToSystemTime(&ftLocalTime, &refSystemTime);
}

template <typename T>
T CBsFS<typename T>::GetModuleFile(HMODULE hModule, HANDLE hProcess/* = nullptr*/) {
	_type szMoudle[MAX_PATH] = {0};
	if (nullptr == hProcess || !bsc::BSOS::IsWin10orLater()) { //Because GetModuleFileNameEx will failed on WIN7 platform
		BsGetModuleFileName(hModule, szMoudle, BsNumElms(szMoudle));
		return szMoudle;
	}
	BsGetModuleFileNameEx(hProcess ? hProcess : GetCurrentProcess(), hModule, szMoudle, BsNumElms(szMoudle));
	return szMoudle;
}

template <typename T>
T CBsFS<typename T>::GetModuleFileDir(HMODULE hModule) {
	_type szMoudle[MAX_PATH] = {0};
	BsGetModuleFileName(hModule, szMoudle, BsNumElms(szMoudle));
	return GetFileDir(T(szMoudle));
}

template <typename T>
T CBsFS<typename T>::GetModuleFileName(HMODULE hModule, HANDLE hProcess/* = nullptr*/) {
	const T strMoudle = GetModuleFile(hModule, hProcess);
	const T strFileName = GetFileName(strMoudle);
	return move(strFileName);
}

template <typename T>
T CBsFS<typename T>::ParentPath(const T& strFilePath) {	
	if (1u >= strFilePath.length()) return T{}; // C => T{}, . => T{}
	T t(strFilePath);
	T strPath = t.Replace(_type(BS_BACKSLASH_CHAR_A), _type(BS_SLASH_CHAR_A));
	if (_type(BS_SLASH_CHAR_A) == strPath.at(strPath.length() - 1u))
		strPath = strPath.substr(0u, strPath.length() - 1u); // Remove the last '\\' character

	if (1u == strPath.length() && _type(BS_DOT_CHAR_A) == strPath.at(0u))
		return T{}; // .\\ => T{}, ./ => T{}

	T::size_type pos = strPath.rfind(_type(BS_COLON_CHAR_A));
	if (pos != T::npos && 3u >= strPath.length())
		return T{}; // C: => T{}, C:\\ => T{}

	map<int, T> oMap;
	SplitPath(strPath, oMap);
	T strDir = oMap[eFS_DIR];
	if (1u == strDir.length() && _type(BS_SLASH_CHAR_A) == strDir.at(0u))
		return move(oMap[eFS_DISK] + strDir); // C:\\abc => C:\\

	const T& strExt = oMap[eFS_EXT];
	if (!strExt.empty()) {
		pos = strDir.rfind(_type(BS_SLASH_CHAR_A));
		if (pos == (strDir.length() - 1u)) {
			pos = strDir.rfind(_type(BS_SLASH_CHAR_A), pos - 1u);
			return move(oMap[eFS_DISK] + strDir.substr(0u, pos+1u)); /* C:\\abc\\..\\..\\123\\abc.txt => C:\\abc\\..\\..\\ */
		}
	}
	return move(oMap[eFS_DISK] + strDir);
}

template <typename T>
T CBsFS<typename T>::GenGUIDFileName(const UINT eFmt /*= E_GUID_FORMAT_NULL*/) {
	if (CGUIDFactory::E_GUID_FORMAT_FULL < eFmt)
		return T{};

	basic_ostringstream<_type, char_traits<_type>, allocator<_type> > ostm;
	ostm.fill(_ctype(BS_ZERO_A));

	unique_ptr<bsc::CGUIDFactory> upGUIDFactory = CGUIDFactory::CreateGUIDFactory();
	if (upGUIDFactory) {
		_type szBuf[100] = {0};
		BOOL bRet = upGUIDFactory->GenGUID(szBuf, sizeof(szBuf), (CGUIDFactory::eGUIDFormat)eFmt);
		ostm << szBuf << _ctype(BS_UNDERSCORE_CHAR_A);
	}

	SYSTEMTIME sysTime = {0};
	GetLocalTime(&sysTime);
	ostm << setw(4) << (int)sysTime.wYear
		<< setw(1) << _ctype(BS_UNDERSCORE_CHAR_A)
		<< setw(2) << (int)sysTime.wMonth // tm_mon范围[0,11],故需加1
		<< setw(1) << _ctype(BS_UNDERSCORE_CHAR_A)
		<< setw(2) << (int)sysTime.wDay
		<< setw(1) << _ctype(BS_UNDERSCORE_CHAR_A)
		<< setw(2) << (int)sysTime.wHour
		<< setw(1) << _ctype(BS_UNDERSCORE_CHAR_A)
		<< setw(2) << (int)sysTime.wMinute
		<< setw(1) << _ctype(BS_UNDERSCORE_CHAR_A)
		<< setw(2) << (int)sysTime.wSecond
		<< setw(1) << _ctype(BS_UNDERSCORE_CHAR_A)
		<< setw(3) << (int)sysTime.wMilliseconds;
	return move(ostm.str());
}
template <typename T>
T CBsFS<typename T>::GetTemporaryFolder(void) _NOEXCEPT {
	_type szTemp[MAX_PATH + 1] = {0};
	BsGetTempPath(MAX_PATH, szTemp);
	return szTemp;
}

template <typename T>
T CBsFS<typename T>::GetTempFileName(const T& strPrefix/* = T()*/, const UINT uUnique/* = 0*/) _NOEXCEPT {
	_type szTmpName[_MAX_PATH] = {0};
	_type szPrefix[] = {_type('~'), _type('b'), _type('s')}; // = _T("~bs")
	const T strTmpDir = GetTemporaryFolder();
	BsGetTempFileName(strTmpDir.c_str(), strPrefix.empty() ? szPrefix : strPrefix.c_str(), uUnique, szTmpName);
	return szTmpName;
}

template <typename T>
T CBsFS<typename T>::ChangeFileExt(const T& strFile, const T& strTargetExt) _NOEXCEPT {
	T::size_type pos = strFile.rfind(_type(BS_DOT_CHAR_A));
	if (pos == T::npos)
		return {};
	const T strFileName = strFile.substr(0, pos + 1);
	return std::move(strFileName + strTargetExt);
}
//[in] A CSIDL value that identifies the folder whose path is to be retrieved.
//Only real folders are valid.If a virtual folder is specified, this function will fail.
//You can force creation of a folder with SHGetFolderPath by combining the folder's CSIDL with CSIDL_FLAG_CREATE.
template <typename T>
T CBsFS<typename T>::GetSpecificFolder(const UINT32 uFolderID) {
	_type path[_MAX_PATH + 1] = {0};
	HRESULT hr = BsSHGetFolderPath(NULL, uFolderID, NULL, 0, path);
	_ASSERT(S_OK == hr);
	return path;
}

template <typename T>
T CBsFS<typename T>::GetShortPathName(const T& strFilePath) _NOEXCEPT {
	if (strFilePath.empty())
		return {};
	_type szPath[MAX_PATH] = {0};
	T strShortPathName = {};
	if (0 != BsGetShortPathName(strFilePath.c_str(), szPath, BsNumElms(szPath)))
		strShortPathName = szPath;
	else
		Log::DebugError(_T("GetShortPathName() failed, err=0x%08x"), GetLastError());
	return move(strShortPathName);
}

template <typename T>
T CBsFS<typename T>::GetUserAppDataFolder(void) _NOEXCEPT {
	return move(GetSpecificFolder(CSIDL_LOCAL_APPDATA));
}

template <typename T>
T CBsFS<typename T>::GetProgramDataFolder(void) _NOEXCEPT {
	return move(GetSpecificFolder(CSIDL_COMMON_APPDATA));
}

template <typename T>
T CBsFS<typename T>::GetProgramFilesFolder(void) _NOEXCEPT {
	return move(GetSpecificFolder(CSIDL_PROGRAM_FILES));
}

template <typename T>
BOOL CBsFS<typename T>::DeleteFile(_ctype* pszPath) {
	return BsDeleteFile(pszPath);
}

template <typename T>
BOOL CBsFS<typename T>::DeleteFile(const T& strFilePath) {
	return BsDeleteFile(strFilePath.c_str());
}

template <typename T>
void CBsFS<typename T>::DeleteFiles(vector<T>& ovtFiles) {
	for each(auto& item in ovtFiles)
		BsDeleteFile(item.c_str());
}

template <typename T>
BOOL CBsFS<typename T>::CopyFile(const T& strFileFrom, const T& strFileTo, const uint64_t ui64Max/* = ULLONG_MAX*/) {
	BOOL bRet = FALSE;
	if (ui64Max >= (uint64_t)GetFileSize(strFileFrom))
		bRet = BsCopyFile(strFileFrom.c_str(), strFileTo.c_str(), FALSE);
	return bRet;
}

template <typename T>
BOOL CBsFS<typename T>::CopyFiles(const T& strFileFrom, const T& strFileTo, const uint64_t ui64Max /*= ULLONG_MAX*/) {
	if (strFileFrom.empty() || strFileTo.empty())
		return FALSE;

	if (!BsPathFileExists(strFileTo.c_str()))
		RecursiveCreateFolder(strFileTo);

	vector<T> files;
	_ctype szAppend[] = { _ctype(BS_STAR_CHAR_A), _ctype(BS_ZERO) };
	const T query = PathAppend(strFileFrom.c_str(), T(szAppend).c_str(), _ctype(BS_SLASH_CHAR_A));
	BOOL bRe = ListSubFiles(query.c_str(), files, MAX_NUMBER_FILES);
	for (vector<T>::const_iterator it = files.begin(); it != files.end(); ++it)
	{
		const T srcFile = PathAppend(strFileFrom.c_str(), it->c_str(), _ctype(BS_SLASH_CHAR_A));
		if (ui64Max > (uint64_t)GetFileSize(srcFile))
		{
			const T dstFile = PathAppend(strFileTo.c_str(), it->c_str(), _ctype(BS_SLASH_CHAR_A));
			BsCopyFile(srcFile.c_str(), dstFile.c_str(), FALSE);
		}
		else
			Log::DebugWarn(_T("%s larger than %lld"), srcFile.c_str(), ui64Max);
	}
	return bRe;
}

template <typename T>
BOOL CBsFS<typename T>::ListSubDirectory(const T& strFolder, vector<T>& vtFolders, const UINT32 uMax/* = ULLONG_MAX*/) {
	return BsListSubDir(strFolder.c_str(), vtFolders, uMax);
}

template <typename T>
BOOL CBsFS<typename T>::ListSubFiles(const T& strFolder, vector<T>& vtFiles, const UINT32 uMax/* = UINT_MAX*/) {
	return BsListSubFiles(strFolder.c_str(), vtFiles, uMax);
}

template <typename T>
BOOL CBsFS<typename T>::ListSubFiles(const T& strFolder, const T& strFilter, vector<T>& vtFiles, const UINT32 uMax/* = UINT_MAX*/) {
	T strFile(strFolder);
	strFile = PathAppend(strFile, strFilter, _ctype(BS_SLASH_CHAR_A));
	return ListSubFiles(strFile.c_str(), vtFiles, uMax);
}

template <typename T>
BOOL CBsFS<typename T>::DeleteFolder(const T& strFolder) {
	return BsDeleteFolder(strFolder.c_str());
}

template <typename T>
BOOL CBsFS<typename T>::TryToDeleteFile(const T& strFilename, const DWORD dwInterval, const DWORD dwDuration) {
	if (BsGetFileStatus(strFilename.c_str())) // If file doesn't exist
		return TRUE;
	const DWORD dwStart = GetTickCount();
	do
	{
		if (BsDeleteFile(strFilename.c_str()))
			return TRUE;
		Sleep(dwInterval);
	} while ((GetTickCount() - dwStart) < dwDuration);
	return FALSE;
}

template <typename T>
BOOL CBsFS<typename T>::RecursiveCreateFolder(const T& strFolder, const UINT32 uFrom = 0) {
	if (strFolder.empty())
		return FALSE;
	
	T strPath(strFolder);
	BOOL bResult = BsCreateDirectory(strPath.c_str(), NULL);
	if (bResult)
	{
		//CGPCSystemUtil::SetSecurityDesc(strPath);
	}
	else
	{
		UINT32 uError = GetLastError();
		switch (uError)
		{
		case ERROR_ALREADY_EXISTS:
			bResult = TRUE;
			break;
		case ERROR_ACCESS_DENIED:
			bResult = FALSE;
			//QLError(_T("recursiveCreate folder failed,path=%s, error=%d,access denied"), strPath.c_str(), uError);
			break;
		case ERROR_PATH_NOT_FOUND:
		{
			if (strPath[strPath.size() - 1] == _ctype(BS_SLASH_CHAR_A))
				strPath = strPath.substr(0, strPath.size() - 1);

			T::size_type pos = strPath.rfind(_ctype(BS_SLASH_CHAR_A));
			if (T::npos != pos)
			{
				T strParent = strPath.substr(0, pos);
				if (RecursiveCreateFolder(strParent))
				{
					bResult = BsCreateDirectory(strPath.c_str(), NULL);
					//////////////////////////////////////////////////////////////////////////
					//2016/05/13, fix target folder security desc
					if (bResult)
					{
						;// CGPCSystemUtil::SetSecurityDesc(strPath);
					}
					//////////////////////////////////////////////////////////////////////////
				}
			}
		}
		break;
		default:
			Log::DebugWarn(_T("RecursiveCreate failed, Path=%s, Err=%d"), strPath.c_str(), uError);
			break;
		}
	}
	return bResult;
}

template <typename T>
BOOL CBsFS<typename T>::BrowseDirectory(const T& strFileName) {
	return BsLocateDirectory(strFileName.c_str());
}

template <typename T>
BOOL CBsFS<typename T>::LaunchBrowser(const T& strExeFileName, const T& strURL) {
	return BsLaunchBrowser(strExeFileName.c_str(), strURL.c_str());
}

template <typename T>
BOOL CBsFS<typename T>::LaunchBat(const T& strBatFile) {
	return BsLaunchBat(strBatFile.c_str());
}

template <typename T>
BOOL CBsFS<typename T>::ReadLine(basic_ifstream<_type, char_traits<_type> >& ifs, T& strLine) {
	strLine.clear();
	BOOL bRet = FALSE;
	if (ifs.is_open() && getline(ifs, strLine))
		bRet = TRUE;
	return bRet;
}

template <typename T>
BOOL CBsFS<typename T>::ReadLines(const T& strFilePath, vector<T>& vtLines) {
	vtLines.clear();
	basic_ifstream<_type, char_traits<_type> > ifs(strFilePath.c_str());
	T strLine{};
	while (ReadLine(ifs, strLine)) {
		vtLines.push_back(move(strLine));
		strLine.erase();
	}
	return (0 < vtLines.size());
}

template <typename T> // MakeUniqueFileName
T CBsFS<typename T>::MkUniFileName(const DWORD dwCount/* = 0u*/, const T& strFileExt/* = T()*/) {
	SYSTEMTIME sysTime = { 0 };
	::GetLocalTime(&sysTime);

	std::basic_ostringstream<_type, std::char_traits<_type>, std::allocator<_type> > ostm;
	ostm.fill(_ctype('0'));
	ostm << std::setw(4) << (DWORD)sysTime.wYear << _ctype('_')
		<< std::setw(2) << (DWORD)sysTime.wMonth << _ctype('_')
		<< std::setw(2) << (DWORD)sysTime.wDay << _ctype('_')
		<< std::setw(2) << (DWORD)sysTime.wHour << _ctype('_')
		<< std::setw(2) << (DWORD)sysTime.wMinute << _ctype('_')
		<< std::setw(2) << (DWORD)sysTime.wSecond << _ctype('_')
		<< std::setw(3) << (DWORD)sysTime.wMilliseconds;

	if (0u < dwCount)
		ostm << _ctype('_') << dwCount;
	if (!strFileExt.empty())
		ostm << strFileExt;
	return std::move(ostm.str());
}
//////////////////////////////////////////////////////////////////////////
END_NS

Tags:

最近发表
标签列表