10

我应该创建两个CFile对象并将一个对象逐个字符复制到另一个对象中吗?或者图书馆里有什么可以为我做这件事的吗?

4

4 回答 4

14

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

于 2008-10-10T15:52:21.057 回答
3

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

  • CopyFile()
  • CopyFileEx()
  • SHFileOperation()
  • IFileOperationSHFileOperation()(在 Vista 中替换)
于 2008-10-14T05:07:11.013 回答
0

虽然我很欣赏前面的答案,但我发现这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;
}
于 2021-04-13T16:10:45.350 回答
0

代码中的 Copy 选项要求首先存在 dest 文件或文件夹,否则 if (CheckPath(sDest) == PATH_NOT_FOUND) 将始终导致错误。

于 2021-04-14T13:43:20.710 回答