C++ 移动文件(大文件移动 IFileOperation::MoveItem)

7 篇文章 0 订阅


由于今天使用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;
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值