博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ 移动文件(大文件移动 IFileOperation::MoveItem)
阅读量:2242 次
发布时间:2019-05-09

本文共 8164 字,大约阅读时间需要 27 分钟。

文章目录

由于今天使用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所替代

IFileOperation::MoveItem

#include 
#include
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;}

转载地址:http://scwdb.baihongyu.com/

你可能感兴趣的文章
【MyBatis学习03】原始dao开发方法及其弊端
查看>>
【MyBatis学习04】mapper代理方法开发dao
查看>>
【MyBatis学习05】SqlMapConfig.xml文件中的配置总结
查看>>
【MyBatis学习06】输入映射和输出映射
查看>>
【MyBatis学习07】动态sql
查看>>
【MyBatis学习08】高级映射之一对一查询
查看>>
【MyBatis学习09】高级映射之一对多查询
查看>>
【MyBatis学习10】高级映射之多对多查询
查看>>
【MyBatis学习11】MyBatis中的延迟加载
查看>>
【MyBatis学习12】MyBatis中的一级缓存
查看>>
【MyBatis学习13】MyBatis中的二级缓存
查看>>
【MyBatis学习14】MyBatis和Spring整合
查看>>
【MyBatis学习15】MyBatis的逆向工程生成代码
查看>>
Java 中 final、finally 和 finalize 使用总结
查看>>
volatile关键字解析
查看>>
单例模式的八种写法比较
查看>>
比较常见的数据库SQL面试题以及答案
查看>>
MySQL与Oracle的区别
查看>>
关于Oracle数据库优化的几点总结
查看>>
69道Spring面试题和答案
查看>>