2017-02-22 62 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