2017-07-18 72 views
-2

下面的代碼演示了當路徑包含一些奇怪的(但有效的)ASCII字符時stat和GetFileAttributes失敗。 作爲一種解決方法,我將使用8.3 DOS文件名。但是,當驅動器禁用8.3名稱時,這不起作用。 (使用fsutil命令禁用了8.3個名稱:fsutil behavior set disable8dot3 1)。在Windows上,包含奇怪字符的路徑的stat和GetFileAttributes失敗

在這種情況下是否可以獲取stat和/或GetFileAttributes? 如果沒有,是否有另一種方式來確定路徑是否是一個目錄或文件?

#include "stdafx.h" 

#include <sys/stat.h> 
#include <string> 
#include <Windows.h> 
#include <atlpath.h> 

std::wstring s2ws(const std::string& s) 
{ 
    int len; 
    int slength = (int)s.length() + 1; 
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len]; 
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len); 
    std::wstring r(buf); 
    delete[] buf; 
    return r; 
} 

// The final characters in the path below are 0xc3 (Ã) and 0x3f (?). 
// Create a test directory with the name à and set TEST_DIR below to your test directory. 
const char* TEST_DIR = "D:\\tmp\\VisualStudio\\TestProject\\ConsoleApplication1\\test_data\\Ã"; 

int main() 
{ 
    std::string testDir = TEST_DIR; 

    // test stat and _wstat 
    struct stat st; 
    const auto statSucceeded = stat(testDir.c_str(), &st) == 0; 
    if (!statSucceeded) 
    { 
     printf("stat failed\n"); 
    } 

    std::wstring testDirW = s2ws(testDir); 

    struct _stat64i32 stW; 
    const auto statSucceededW = _wstat(testDirW.data(), &stW) == 0; 
    if (!statSucceededW) 
    { 
     printf("_wstat failed\n"); 
    } 

    // test PathIsDirectory 
    const auto isDir = PathIsDirectory(testDirW.c_str()) != 0; 
    if (!isDir) 
    { 
     printf("PathIsDirectory failed\n"); 
    } 

    // test GetFileAttributes 
    const auto fileAttributes = ::GetFileAttributes(testDirW.c_str()); 
    const auto getFileAttributesWSucceeded = fileAttributes != INVALID_FILE_ATTRIBUTES; 
    if (!getFileAttributesWSucceeded) 
    { 
     printf("GetFileAttributes failed\n"); 
    } 

    return 0; 
} 
+1

*「奇怪(但有效)的ASCII字符」* - ASCII僅定義範圍爲0x00至0x7f的字符。 0xc3不在ASCII的域內。 – cdhowie

+0

_Win_特定的解決方法:使用'wchar_t'而不是'char'(甚至更好:[\ [MSDN \]:TCHAR](https://msdn.microsoft.com/zh-cn/library/office/cc842072.aspx )),並使用[\ [MSDN \]:GetFileAttributesW函數](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v = vs.85).aspx)(和[\ [MSDN \]:_wstat](https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx))__explicitly__(no's2ws','wstring',...)。 – CristiFati

回答

1

您遇到的問題來自使用MultiByteToWideChar函數。使用CP_ACP可以默認爲不支持某些字符的代碼頁。如果您將默認的系統代碼頁面更改爲UTF8,則您的代碼將起作用。由於您無法告訴您的客戶端使用哪個代碼頁,因此可以使用第三方庫(例如Unicode國際組件)將主機代碼頁轉換爲UTF16。

我使用控制檯代碼頁65001和VS2015運行了您的代碼,並且您的代碼按照書面方式工作。我還添加了積極的printfs來驗證它是否有效。

1

不要以狹窄的字符串字面值開始,並嘗試轉換它,從寬字符串字面值開始 - 代表實際文件名。您可以使用十六進制轉義序列來避免對源代碼編碼的依賴。

如果實際的代碼不使用字符串文字,最好的分辨率取決於情況;例如,如果正在從文件讀取文件名,則需要確保知道文件的編碼格式,並相應地執行轉換。

如果實際代碼從命令行參數中讀取文件名,則可以使用wmain()而不是main()來獲取寬字符串的參數。