2017-02-22 84 views
1

我在寫一個有錯誤的備份程序。用調試器遍歷代碼,我發現刪除文件時出現錯誤。DeleteFile()失敗,但文件存在(很長的文件名)

我使用CFileFind查找文件,我用CFileFind::GetFilePath()獲得的全路徑名。

CFileFind find; 
BOOL bContinue = find.FindFile(AppendPath(lpszPath, _T("*"))); 
while (bContinue) 
{ 
    bContinue = find.FindNextFile(); 
    if (!find.IsDirectory()) 
    { 
     if (find.IsReadOnly()) 
      ClearReadOnlyAttribute(find); 
     if (!::DeleteFile(find.GetFilePath())) 
      return false; 
    } 
} 

DeleteFile()正在返回FALSE,和GetLastError()將返回3(ERROR_PATH_NOT_FOUND),並且是在其它情況下返回圖2(ERROR_FILE_NOT_FOUND)。

正如你所看到的,我第一次嘗試刪除只讀屬性,如果它被設置;但是,我可以看到文件存在並且沒有隻讀屬性。

有一點要注意的是,文件名非常長。這段代碼實際上已經過測試,並且工作得很好,文件名較短。在這種情況下,find.GetFilePath()回報:

\\ Readyshare \ USB 3 \備份\ DRIVEZ_BACKUP \斯泰西\備份0001 \音樂\將被刪除\ iTunes的\ iTunes的媒體\音樂\戴夫·馬修斯樂隊\距世界(豪華版)\遠離世界(豪華Version.itlp \音頻\ DaveMatthewsBand_AwayFromTheWorld_backgroundaudio.m4a

,這看起來是正確的。如果我複製所有但文件名到Windows資源管理器,它讓我看到該文件夾​​。而文件夾中存在那裏。

有誰知道爲什麼DeleteFile()事實上它會告訴我路徑或文件不存在嗎?

UPDATE:

基於布魯諾·費雷拉的回答,我通過以下方法運行我的文件名。 (對不起,老CString的風格的代碼,我更新舊的MFC程序。)

CString CBackupWorker::ConvertToExtendedLengthPath(LPCTSTR pszPath) 
{ 
    CString s(pszPath); 

    if (s.GetLength() >= MAX_PATH) 
    { 
     if (::isalpha(s[0]) && s[1] == ':') 
     { 
      s.Insert(0, _T("\\\\?\\")); 
     } 
     else if (s[0] == '\\' && s[1] == '\\') 
     { 
      s.Delete(0, 2); 
      s.Insert(0, _T("\\\\\?\\UNC\\")); 
     } 
    } 
    return s; 
} 

正如你所看到的代碼,如果文件名超過MAX_PATH預先考慮相應的前綴。根據路徑是否指定網絡路徑,採取步驟追加適當的前綴。

我不知道爲什麼有人做這個令人難以置信的混亂。如果Windows允許您指定更長的名稱,我真的不會看到向後兼容性問題。在Windows 10中,有一個註冊表設置可以更改,這樣就不需要這個廢話。但當然,我不希望我的軟件限制到Windows 10

+1

尼斯。沒有解釋的downvote。這非常沒有生氣。我怎麼可能提供比我在這裏更多的細節? –

+0

'\ Readyshare \ ...'這正是路徑?或者可能是'\\ Readyshare \ ...'文件不是本地的? – RbMm

+0

路徑從兩條反斜槓開始,就像我在我的問題中那樣。這是*確切的*路徑。它在連接到我的路由器的USB驅動器上。直到我由於目錄結構而開始獲取這些較長的文件名時,我纔有任何問題。 –

回答

7

只有微調版本從MSDN

參數

lpFileName的對象[IN]的文件的名稱是刪除。在該函數的ANSI 版本中,名稱僅限於MAX_PATH字符。 要將此限制擴展爲32,767個寬字符,請調用該函數的Unicode 版本並將「\\?\」前置到路徑中。有關更多 信息,請參閱命名文件。

基本上,你應該呼籲本地路徑DeleteFileW前面加上\\?\\\?\UNC\遠程路徑是這樣的:

CFileFind find; 
BOOL bContinue = find.FindFile(AppendPath(lpszPath, _T("*"))); 
while (bContinue) 
{ 
    bContinue = find.FindNextFile(); 
    if (!find.IsDirectory()) 
    { 
     if (find.IsReadOnly()) 
      ClearReadOnlyAttribute(find); 

     CString path = find.GetFilePath(); 
     if (path.GetLength() >= MAX_PATH) 
     { 
      if (PathIsUNC(path)) { 
       path.TrimLeft(_T("\\")); 
       path.Insert(0, _T("\\\\?\\UNC\\")); 
      } 
      else 
       path.Insert(0, _T("\\\\?\\")); 
     } 

     if (!::DeleteFileW(path)) 
      return false; 
    } 
} 
+1

'\\?\'前綴只適用於本地文件系統的絕對路徑,不適用於網絡路徑 – RbMm

+2

@RbMm從MSDN:'\\?\「前綴也可以用於根據通用命名約定(UNC)。要使用UNC指定這樣的路徑,請使用「\\?\ UNC \」前綴。例如,「\\?\ UNC \ server \ share」,其中「server」是計算機的名稱,「share」是共享文件夾的名稱。「https://msdn.microsoft.com/pt- br/library/windows/desktop/aa365247(v = vs.85).aspx –

+0

這是 - '\\?\ UNC \'會工作,但在你的代碼中是'\\?\'什麼是錯的。真正當win32子系統查看'\\?\'前綴時,只需將其轉換爲'\ ?? \'' – RbMm