代码之家  ›  专栏  ›  技术社区  ›  Tommy Herbert

在MFC应用程序中,将文件从一个目录复制到另一个目录的最简单方法是什么?

  •  10
  • Tommy Herbert  · 技术社区  · 17 年前

    我应该创建两个吗 CFile 将一个对象复制到另一个角色中?或者图书馆里有什么东西可以为我做这件事吗?

    4 回复  |  直到 4 年前
        1
  •  13
  •   jeffm    5 年前

    我只会用 CopyFile Win32 API函数,但中的示例代码 CFile::Open 文档显示了如何使用以下工具复制文件 CFile (几乎使用你建议的方法)。

        2
  •  2
  •   skst    17 年前

    这取决于你想做什么。有很多方法可以复制文件:

    • CopyFile()
    • CopyFileEx()
    • SHFileOperation()
    • IFileOperation (替换 SHFileOperation() 在Vista中)
        3
  •  0
  •   user8128167    5 年前

    虽然我很欣赏之前的答案,但我发现 FileOperations 是一个很好的包装器,它模仿了Windows资源管理器中执行复制操作的方式,其中还包括复制、移动和删除文件以及重命名目录:

    http://www.ucancode.net/Visual_C_Source_Code/Copy-Move-Delete-files-rename-directories-SHFileOperation-CFileFind-FindFirstFile-FindNextFile-mfc-example.htm

    #include "stdafx.h"
    #include "FileOperations.h"
    //
    // this code copy 'c:\source' directory and 
    // all it's subdirectories and files
    // to the 'c:\dest' directory. 
    //
    CFileOperation fo;      // create object
    fo.SetOverwriteMode(false); // reset OverwriteMode flag (optional)
    if (!fo.Copy("c:\\source", "c:\\dest")) // do Copy
    {
        fo.ShowError(); // if copy fails show error message
    }
    //
    // this code delete 'c:\source' directory and 
    // all it's subdirectories and files.
    //
    fo.Setucancode.netIfReadOnly();   // set ucancode.netIfReadonly flag (optional)
    if (!fo.Delete("c:\\source")) // do Copy
    {
        fo.ShowError(); // if copy fails show error message
    }
    

    以下是完整性的源代码:

    #include "resource.h"
    
    #define PATH_ERROR          -1
    #define PATH_NOT_FOUND      0
    #define PATH_IS_FILE        1
    #define PATH_IS_FOLDER      2
    
    
    class CFExeption
    {
    public:
        CFExeption(DWORD dwErrCode);
        CFExeption(CString sErrText);
        CString GetErrorText() {return m_sError;}
        DWORD GetErrorCode() {return m_dwError;}
    
    private:
        CString m_sError;
        DWORD m_dwError;
    };
    
    
    //*****************************************************************************************************
    
    class CFileOperation
    {
    public:
        CFileOperation(); // constructor
        bool Delete(CString sPathName); // delete file or folder
        bool Copy(CString sSource, CString sDest); // copy file or folder
        bool Replace(CString sSource, CString sDest); // move file or folder
        bool Rename(CString sSource, CString sDest); // rename file or folder
        CString GetErrorString() {return m_sError;} // return error description
        DWORD GetErrorCode() {return m_dwError;} // return error code
        void ShowError() // show error message
            {MessageBox(NULL, m_sError, _T("Error"), MB_OK | MB_ICONERROR);}
        void SetAskIfReadOnly(bool bAsk = true) // sets behavior with readonly files(folders)
            {m_bAskIfReadOnly = bAsk;}
        bool IsAskIfReadOnly() // return current behavior with readonly files(folders)
            {return m_bAskIfReadOnly;}
        bool CanDelete(CString sPathName); // check attributes
        void SetOverwriteMode(bool bOverwrite = false) // sets overwrite mode on/off
            {m_bOverwriteMode = bOverwrite;}
        bool IsOverwriteMode() {return m_bOverwriteMode;} // return current overwrite mode
        int CheckPath(CString sPath);
        bool IsAborted() {return m_bAborted;}
    
    protected:
        void DoDelete(CString sPathName);
        void DoCopy(CString sSource, CString sDest, bool bDelteAfterCopy = false);
        void DoFileCopy(CString sSourceFile, CString sDestFile, bool bDelteAfterCopy = false);
        void DoFolderCopy(CString sSourceFolder, CString sDestFolder, bool bDelteAfterCopy = false);
        void DoRename(CString sSource, CString sDest);
        bool IsFileExist(CString sPathName);
        void PreparePath(CString &sPath);
        void Initialize();
        void CheckSelfRecursion(CString sSource, CString sDest);
        bool CheckSelfCopy(CString sSource, CString sDest);
        CString ChangeFileName(CString sFileName);
        CString ParseFolderName(CString sPathName);
    
    private:
        CString m_sError;
        DWORD m_dwError;
        bool m_bAskIfReadOnly;
        bool m_bOverwriteMode;
        bool m_bAborted;
        int m_iRecursionLimit;
    };
    
    
    //*****************************************************************************************************
    

    C++文件:

    #include "stdafx.h" 
    #include "resource.h" 
    #include "FileOperations.h" 
    
    //************************************************************************************************************
    CFExeption::CFExeption(DWORD dwErrCode)
    {
        LPVOID lpMsgBuf;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL, dwErrCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
        m_sError = (LPTSTR)lpMsgBuf;
        LocalFree(lpMsgBuf);
        m_dwError = dwErrCode;
    }
    
    
    CFExeption::CFExeption(CString sErrText)
    {
        m_sError = sErrText;
        m_dwError = 0;
    }
    
    
    //************************************************************************************************************
    
    CFileOperation::CFileOperation()
    {
        Initialize();
    }
    
    
    void CFileOperation::Initialize()
    {
        m_sError = _T("No error");
        m_dwError = 0;
        m_bAskIfReadOnly = true;
        m_bOverwriteMode = false;
        m_bAborted = false;
        m_iRecursionLimit = -1;
    }
    
    
    void CFileOperation::DoDelete(CString sPathName)
    {
        CFileFind ff;
        CString sPath = sPathName;
    
        if (CheckPath(sPath) == PATH_IS_FILE)
        {
            if (!CanDelete(sPath)) 
            {
                m_bAborted = true;
                return;
            }
            if (!DeleteFile(sPath)) throw new CFExeption(GetLastError());
            return;
        }
    
        PreparePath(sPath);
        sPath += "*.*";
    
        BOOL bRes = ff.FindFile(sPath);
        while(bRes)
        {
            bRes = ff.FindNextFile();
            if (ff.IsDots()) continue;
            if (ff.IsDirectory())
            {
                sPath = ff.GetFilePath();
                DoDelete(sPath);
            }
            else DoDelete(ff.GetFilePath());
        }
        ff.Close();
        if (!RemoveDirectory(sPathName) && !m_bAborted) throw new CFExeption(GetLastError());
    }
    
    
    void CFileOperation::DoFolderCopy(CString sSourceFolder, CString sDestFolder, bool bDelteAfterCopy)
    {
        CFileFind ff;
        CString sPathSource = sSourceFolder;
        BOOL bRes = ff.FindFile(sPathSource);
        while (bRes)
        {
            bRes = ff.FindNextFile();
            if (ff.IsDots()) continue;
            if (ff.IsDirectory()) // source is a folder
            {
                if (m_iRecursionLimit == 0) continue;
                sPathSource = ff.GetFilePath() + CString("\\") + CString("*.*");
                CString sPathDest = sDestFolder + ff.GetFileName() + CString("\\");
                if (CheckPath(sPathDest) == PATH_NOT_FOUND) 
                {
                    if (!CreateDirectory(sPathDest, NULL))
                    {
                        ff.Close();
                        throw new CFExeption(GetLastError());
                    }
                }
                if (m_iRecursionLimit > 0) m_iRecursionLimit --;
                DoFolderCopy(sPathSource, sPathDest, bDelteAfterCopy);
            }
            else // source is a file
            {
                CString sNewFileName = sDestFolder + ff.GetFileName();
                DoFileCopy(ff.GetFilePath(), sNewFileName, bDelteAfterCopy);
            }
        }
        ff.Close();
    }
    
    
    bool CFileOperation::Delete(CString sPathName)
    {
        try
        {
            DoDelete(sPathName);
        }
        catch(CFExeption* e)
        {
            m_sError = e->GetErrorText();
            m_dwError = e->GetErrorCode();
            delete e;
            if (m_dwError == 0) return true;
            return false;
        }
        return true;
    }
    
    
    bool CFileOperation::Rename(CString sSource, CString sDest)
    {
        try
        {
            DoRename(sSource, sDest);
        }
        catch(CFExeption* e)
        {
            m_sError = e->GetErrorText();
            m_dwError = e->GetErrorCode();
            delete e;
            return false;
        }
        return true;
    }
    
    
    void CFileOperation::DoRename(CString sSource, CString sDest)
    {
        if (!MoveFile(sSource, sDest)) throw new CFExeption(GetLastError());
    }
    
    
    void CFileOperation::DoCopy(CString sSource, CString sDest, bool bDelteAfterCopy)
    {
        CheckSelfRecursion(sSource, sDest);
        // source not found
        if (CheckPath(sSource) == PATH_NOT_FOUND)
        {
            CString sError = sSource + CString(" not found");
            throw new CFExeption(sError);
        }
        // dest not found
        if (CheckPath(sDest) == PATH_NOT_FOUND)
        {
            CString sError = sDest + CString(" not found");
            throw new CFExeption(sError);
        }
        // folder to file
        if (CheckPath(sSource) == PATH_IS_FOLDER && CheckPath(sDest) == PATH_IS_FILE) 
        {
            throw new CFExeption("Wrong operation");
        }
        // folder to folder
        if (CheckPath(sSource) == PATH_IS_FOLDER && CheckPath(sDest) == PATH_IS_FOLDER) 
        {
            CFileFind ff;
            CString sError = sSource + CString(" not found");
            PreparePath(sSource);
            PreparePath(sDest);
            sSource += "*.*";
            if (!ff.FindFile(sSource)) 
            {
                ff.Close();
                throw new CFExeption(sError);
            }
            if (!ff.FindNextFile()) 
            {
                ff.Close();
                throw new CFExeption(sError);
            }
            CString sFolderName = ParseFolderName(sSource);
            if (!sFolderName.IsEmpty()) // the source is not drive
            {
                sDest += sFolderName;
                PreparePath(sDest);
                if (!CreateDirectory(sDest, NULL))
                {
                    DWORD dwErr = GetLastError();
                    if (dwErr != 183)
                    {
                        ff.Close();
                        throw new CFExeption(dwErr);
                    }
                }
            }
            ff.Close();
            DoFolderCopy(sSource, sDest, bDelteAfterCopy);
        }
        // file to file
        if (CheckPath(sSource) == PATH_IS_FILE && CheckPath(sDest) == PATH_IS_FILE) 
        {
            DoFileCopy(sSource, sDest);
        }
        // file to folder
        if (CheckPath(sSource) == PATH_IS_FILE && CheckPath(sDest) == PATH_IS_FOLDER) 
        {
            PreparePath(sDest);
            char drive[MAX_PATH], dir[MAX_PATH], name[MAX_PATH], ext[MAX_PATH];
            _splitpath(sSource, drive, dir, name, ext);
            sDest = sDest + CString(name) + CString(ext);
            DoFileCopy(sSource, sDest);
        }
    }
    
    
    void CFileOperation::DoFileCopy(CString sSourceFile, CString sDestFile, bool bDelteAfterCopy)
    {
        BOOL bOvrwriteFails = FALSE;
        if (!m_bOverwriteMode)
        {
            while (IsFileExist(sDestFile)) 
            {
                sDestFile = ChangeFileName(sDestFile);
            }
            bOvrwriteFails = TRUE;
        }
        if (!CopyFile(sSourceFile, sDestFile, bOvrwriteFails)) throw new CFExeption(GetLastError());
        if (bDelteAfterCopy)
        {
            DoDelete(sSourceFile);
        }
    }
    
    
    bool CFileOperation::Copy(CString sSource, CString sDest)
    {
        if (CheckSelfCopy(sSource, sDest)) return true;
        bool bRes;
        try
        {
            DoCopy(sSource, sDest);
            bRes = true;
        }
        catch(CFExeption* e)
        {
            m_sError = e->GetErrorText();
            m_dwError = e->GetErrorCode();
            delete e;
            if (m_dwError == 0) bRes = true;
            bRes = false;
        }
        m_iRecursionLimit = -1;
        return bRes;
    }
    
    
    bool CFileOperation::Replace(CString sSource, CString sDest)
    {
        if (CheckSelfCopy(sSource, sDest)) return true;
        bool bRes;
        try
        {
            bool b = m_bAskIfReadOnly;
            m_bAskIfReadOnly = false;
            DoCopy(sSource, sDest, true);
            DoDelete(sSource);
            m_bAskIfReadOnly = b;
            bRes = true;
        }
        catch(CFExeption* e)
        {
            m_sError = e->GetErrorText();
            m_dwError = e->GetErrorCode();
            delete e;
            if (m_dwError == 0) bRes = true;
            bRes = false;
        }
        m_iRecursionLimit = -1;
        return bRes;
    }
    
    
    CString CFileOperation::ChangeFileName(CString sFileName)
    {
        CString sName, sNewName, sResult;
        char drive[MAX_PATH];
        char dir  [MAX_PATH];
        char name [MAX_PATH];
        char ext  [MAX_PATH];
        _splitpath((LPCTSTR)sFileName, drive, dir, name, ext);
        sName = name;
    
        int pos = sName.Find("Copy ");
        if (pos == -1)
        {
            sNewName = CString("Copy of ") + sName + CString(ext);
        }
        else
        {
            int pos1 = sName.Find('(');
            if (pos1 == -1)
            {
                sNewName = sName;
                sNewName.Delete(0, 8);
                sNewName = CString("Copy (1) of ") + sNewName + CString(ext);
            }
            else
            {
                CString sCount;
                int pos2 = sName.Find(')');
                if (pos2 == -1)
                {
                    sNewName = CString("Copy of ") + sNewName + CString(ext);
                }
                else
                {
                    sCount = sName.Mid(pos1 + 1, pos2 - pos1 - 1);
                    sName.Delete(0, pos2 + 5);
                    int iCount = atoi((LPCTSTR)sCount);
                    iCount ++;
                    sNewName.Format("%s%d%s%s%s", "Copy (", iCount, ") of ", (LPCTSTR)sName, ext);
                }
            }
        }
    
        sResult = CString(drive) + CString(dir) + sNewName;
    
        return sResult;
    }
    
    
    bool CFileOperation::IsFileExist(CString sPathName)
    {
        HANDLE hFile;
        hFile = CreateFile(sPathName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
        if (hFile == INVALID_HANDLE_VALUE) return false;
        CloseHandle(hFile);
        return true;
    }
    
    
    int CFileOperation::CheckPath(CString sPath)
    {
        DWORD dwAttr = GetFileAttributes(sPath);
        if (dwAttr == 0xffffffff) 
        {
            if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND) 
                return PATH_NOT_FOUND;
            return PATH_ERROR;
        }
        if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) return PATH_IS_FOLDER;
        return PATH_IS_FILE;
    }
    
    
    void CFileOperation::PreparePath(CString &sPath)
    {
        if(sPath.Right(1) != "\\") sPath += "\\";
    }
    
    
    bool CFileOperation::CanDelete(CString sPathName)
    {
        DWORD dwAttr = GetFileAttributes(sPathName);
        if (dwAttr == -1) return false;
        if (dwAttr & FILE_ATTRIBUTE_READONLY)
        {
            if (m_bAskIfReadOnly)
            {
                CString sTmp = sPathName;
                int pos = sTmp.ReverseFind('\\');
                if (pos != -1) sTmp.Delete(0, pos + 1);
                CString sText = sTmp + CString(" is read olny. Do you want delete it?");
                int iRes = MessageBox(NULL, sText, _T("Warning"), MB_YESNOCANCEL | MB_ICONQUESTION);
                switch (iRes)
                {
                    case IDYES:
                    {
                        if (!SetFileAttributes(sPathName, FILE_ATTRIBUTE_NORMAL)) return false;
                        return true;
                    }
                    case IDNO:
                    {
                        return false;
                    }
                    case IDCANCEL:
                    {
                        m_bAborted = true;
                        throw new CFExeption(0);
                        return false;
                    }
                }
            }
            else
            {
                if (!SetFileAttributes(sPathName, FILE_ATTRIBUTE_NORMAL)) return false;
                return true;
            }
        }
        return true;
    }
    
    
    CString CFileOperation::ParseFolderName(CString sPathName)
    {
        CString sFolderName = sPathName;
        int pos = sFolderName.ReverseFind('\\');
        if (pos != -1) sFolderName.Delete(pos, sFolderName.GetLength() - pos);
        pos = sFolderName.ReverseFind('\\');
        if (pos != -1) sFolderName = sFolderName.Right(sFolderName.GetLength() - pos - 1);
        else sFolderName.Empty();
        return sFolderName;
    }
    
    
    void CFileOperation::CheckSelfRecursion(CString sSource, CString sDest)
    {
        if (sDest.Find(sSource) != -1)
        {
            int i = 0, count1 = 0, count2 = 0;
            for(i = 0; i < sSource.GetLength(); i ++)   if (sSource[i] == '\\') count1 ++;
            for(i = 0; i < sDest.GetLength(); i ++) if (sDest[i] == '\\') count2 ++;
            if (count2 >= count1) m_iRecursionLimit = count2 - count1;
        }
    }
    
    
    bool CFileOperation::CheckSelfCopy(CString sSource, CString sDest)
    {
        bool bRes = false;
        if (CheckPath(sSource) == PATH_IS_FOLDER)
        {
            CString sTmp = sSource;
            int pos = sTmp.ReverseFind('\\');
            if (pos != -1)
            {
                sTmp.Delete(pos, sTmp.GetLength() - pos);
                if (sTmp.CompareNoCase(sDest) == 0) bRes = true;
            }
        }
        return bRes;
    }
    
        4
  •  0
  •   uabf9    5 年前

    代码中的“复制”选项要求目标文件或文件夹首先存在,否则 if(检查路径(sDest)==PATH_NOT_FOUND) 总是会导致错误。