由于今天使用windows提供的 MoveFile 移动文件出现问题,特此总结。
MoveFile
这是windows提供的一个API。用法比较简单,并且可以移动文件夹下面子文件。
//将C盘中的test文本移动到D盘
MoveFile("C:\\test.txt", "D:\\test.txt");
原型
BOOL MoveFile(
LPCTSTR lpExistingFileName,
LPCTSTR lpNewFileName
);
简单的说,就是MoveFile(A, B), 将A移动到B
返回值:
- 如果函数成功,则返回值为非零值。
- 如果函数失败,则返回值为零。要获取扩展错误信息,可以调用 GetLastError。
注意:
- B一定要自己起个名字,否则移动不会成功。例如:
//失败
MoveFile("C:\\吞吐量.txt", "D:");
- 拷贝大文件不会成功。错误值为 5 (目前答主也不太清楚为什么)
MoveFileEx
这也是windows提供的API。功能和MoveFile一样,但不同的是这个API可=可以指定移动的方式
原型
BOOL MoveFileEx(
LPCTSTR lpExistingFileName, // file name
LPCTSTR lpNewFileName, // new file name
DWORD dwFlags // move options
);
其中第三个参数可以指定:
MOVEFILE_COPY_ALLOWED //如移动到一个不同的卷,则复制文件并删除原来的文件。
MOVEFILE_CREATE_HARDLINK //系统保留,以供将来使用。
MOVEFILE_REPLACE_EXISTING //如目标文件存在,则将其替换 。
MOVEFILE_DELAY_UNTIL_REBOOT //移动操作在系统下次重新启动时正式进行。
MOVEFILE_FAIL_IF_NOT_TRACKABLE //如果来源文件是一个 LINK 文件,但是文件在移动后不能够被 TRACKED,则函数执行失败。如果目标文件在一个 FAT 格式的文件系统上,则上述情况可以发生。这个参数不支持NT 系统。(我想这里说的可能是移动快捷方式的情况,如果快捷方式指定的目标文件不存在或无法定位,则操作失败,由于没有时间测试,暂时这样理解。)
MOVEFILE_WRITE_THROUGH //这个标记允许函数在执行完文件移动操作后才返回,否则不等文件移动完毕就直接返回。如果设置了 MOVEFILE_DELAY_UNTIL_REBOOT 标记,则 MOVEFILE_WRITE_THROUGH 标记将被忽略。
但今天我从C盘移动一个10G的文件到D盘,这两个函数都不会执行成功。其中MoveFile错误值为5 、MoveFileEx() 错误值为17。于是就不得不采用另一种方法。
Move
bool Move(char *pTo, char *pFrom)
{
SHFILEOPSTRUCT FileOp = { 0 };
FileOp.fFlags = FOF_NOCONFIRMATION | //不出现确认对话框
FOF_NOCONFIRMMKDIR; //需要时直接创建一个文件夹,不需用户确定
FileOp.pFrom = pFrom;
FileOp.pTo = pTo;
FileOp.wFunc = FO_MOVE;
return SHFileOperation(&FileOp) == 0;
}
int main()
{
Move("D:", "C:\\顺序测试");
system("pause");
return 0;
}
这个函数需要自己实现,就可以直接调用。其中和上述两个不同的是,参数。Move(A, B)表示从B移动到A。并且可以移动大文件。并且可以不用指定A中的文件名,只需路径即可
但由于博主的代码在Release版本下测试的时候,上述函数会被直接优化掉,就不会执行移动的操作。但如果单独把该函数拿出来在Release版本测试就没问题。百思不得其解…后来查到,该函数以及被舍弃了,被IFileOperation所替代
Microsoft此函数官网链接
IFileOperation::MoveItem
#include <windows.h>
#include <Shobjidl.h>
using namespace std;
HRESULT Movefile(__in PCWSTR pszSrcItem, __in PCWSTR pszDest, PCWSTR pszNewName)
{
//
// Initialize COM as STA.
//
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOperation *pfo;
//
// Create the IFileOperation interface
//
hr = CoCreateInstance(CLSID_FileOperation,
NULL,
CLSCTX_ALL,
IID_PPV_ARGS(&pfo));
if (SUCCEEDED(hr))
{
// Set the operation flags. Turn off all UI from being shown to the
// user during the operation. This includes error, confirmation,
// and progress dialogs.
hr = pfo->SetOperationFlags(FOF_NO_UI);
if (SUCCEEDED(hr))
{
// Create an IShellItem from the supplied source path.
IShellItem *psiFrom = NULL;
hr = SHCreateItemFromParsingName(pszSrcItem,
NULL,
IID_PPV_ARGS(&psiFrom));
if (SUCCEEDED(hr))
{
IShellItem *psiTo = NULL;
if (NULL != pszDest)
{
// Create an IShellItem from the supplied
// destination path.
hr = SHCreateItemFromParsingName(pszDest,
NULL,
IID_PPV_ARGS(&psiTo));
}
if (SUCCEEDED(hr))
{
// Add the operation
hr = pfo->MoveItem(psiFrom, psiTo, pszNewName, NULL);
if (NULL != psiTo)
{
psiTo->Release();
}
}
psiFrom->Release();
}
if (SUCCEEDED(hr))
{
// Perform the operation to copy the file.
hr = pfo->PerformOperations();
}
}
// Release the IFileOperation interface.
pfo->Release();
}
CoUninitialize();
}
return hr;
}
int main()
{
Movefile(L"C:\\顺序测试", L"D:", NULL);
system("pause");
return 0;
}
该函数能够实现从 C盘的顺序测试文件拷贝到D盘。
递归遍历移动
使用的是boost库中的函数:boost::filesystem
前提:需要安装boost库
头文件:#include <experimental/filesystem>
#include <boost/filesystem.hpp>
static void SetLastErr(const int count, ...)
{
slastErr = " ";
va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i)
{
slastErr += va_arg(args, std::string);
}
va_end(args);
}
static bool CopyFileToDir(const boost::filesystem::path& srcPath, const boost::filesystem::path& desPath, bool override)
{
boost::system::error_code ec;
if (!boost::filesystem::exists(srcPath, ec))
{
cout << "without src path:" << srcPath << endl;
return false;
}
if (!boost::filesystem::exists(desPath, ec) || !boost::filesystem::is_directory(desPath, ec))
{
boost::filesystem::create_directories(desPath, ec);
if (ec)
{
cout << "create_directories faild:" << ec.message() << " | desPath:" << desPath.string() << endl;
return false;
}
}
boost::filesystem::directory_iterator it_end;
for (boost::filesystem::directory_iterator it(srcPath); it != it_end; ++it)
{
boost::filesystem::path p = it->path();
const boost::filesystem::path newSrc = srcPath / it->path().filename();
const boost::filesystem::path newDst = desPath / it->path().filename();
if (boost::filesystem::is_directory(newSrc, ec))
{
CopyFileToDir(newSrc, newDst, override);
}
else
{
if (boost::filesystem::exists(newDst, ec) && override)
{
boost::filesystem::remove(newDst, ec);
if (ec)
{
cout << "remove newfile faild:" << ec.message() << " | file:" << newDst.string() << endl;
return false;
}
}
boost::filesystem::copy_file(newSrc, newDst, ec);
if (ec)
{
cout << "copy_file to newfile faild:" << ec.message() << " | src:" << newSrc.string() << " | newDst:" << newDst.string() << endl;
return false;
}
}
}
return true;
}
bool DeleteDir(const std::wstring & path)
{
std::error_code err;
auto ret = std::experimental::filesystem::remove_all(path, err);
auto msg = err.message();
if (!ret)
{
cout << "DeleteDir failed:" << endl;
return false;
}
return true;
}
bool CopyDir(const std::wstring & src, const std::wstring & dst)
{
return CopyFileToDir(boost::filesystem::path(src), boost::filesystem::path(dst), true);
}
bool MoveDir(const std::wstring & src, const std::wstring & dst)
{
return CopyDir(src, dst) && DeleteDir(src);
}
递归删除
使用的是boost库中的函数:boost::filesystem
前提:需要安装boost库
头文件:#include <experimental/filesystem>
#include <boost/filesystem.hpp>
bool Delete(const boost::filesystem::path& srcPath, bool override)
{
boost::system::error_code ec;
if (!boost::filesystem::exists(srcPath, ec))
{
cout << "without src path:" << srcPath << endl;
return false;
}
boost::filesystem::directory_iterator it_end;
for (boost::filesystem::directory_iterator it(srcPath); it != it_end; ++it)
{
boost::filesystem::path p = it->path();
const boost::filesystem::path newSrc = srcPath / it->path().filename();
if (boost::filesystem::is_directory(newSrc, ec))
{
Delete(newSrc, override);
}
boost::filesystem::remove(newSrc, ec);
LOG_WARN << "remove: " << newSrc << " " << ec;
if (ec)
{
cout << "copy_file to newfile faild:" << ec.message() << " | src:" << newSrc.string() << endl;
return false;
}
}
remove(srcPath, ec);
return true;
}