2017-07-18 12 views
-2

以下のコードは、パスに奇妙な(ただし有効な)ASCII文字が含まれている場合にstatとGetFileAttributesが失敗する方法を示しています。 回避策として、8.3 DOSファイル名を使用します。しかし、ドライブに8.3の名前が無効になっている場合、これは機能しません。 (8.3の名前はfsutilコマンドで無効になります:fsutilの動作セット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_具体的な回避策: 'char'の代わりに' wchar_t'を使用してください(または\ [MSDN \]:TCHAR](https://msdn.microsoft.com/en-us/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__( 's2ws'、' wstring'、...)。 – CristiFati

答えて

1

問題は、MultiByteToWideChar関数の使用に起因しています。 CP_ACPを使用すると、デフォルトでいくつかの文字をサポートしないコードページにすることができます。デフォルトのシステムコードページをUTF8に変更すると、コードが機能します。クライアントにどのコードページを使用するかを伝えることはできないため、Unicodeなどのサードパーティライブラリを使用して、ホストコードページからUTF16に変換することができます。

コンソールコードページ65001とVS2015を使用してコードを実行しましたが、あなたのコードは書かれたとおりに動作しました。私はそれがうまくいったことを確認するために肯定的なprintfsも追加しました。

1

狭い文字列リテラルで始めて変換しないでください。実際のファイル名を表すワイド文字列リテラルから始めてください。 16進数のエスケープシーケンスを使用して、ソースコードのエンコーディングに依存しないようにすることができます。

実際のコードで文字列リテラルが使用されない場合、最適な解像度は状況によって異なります。たとえば、ファイル名がファイルから読み取られている場合は、そのファイルがどのエンコーディングであるかを確認し、それに応じて変換を実行する必要があります。

実際のコードがコマンドライン引数からファイル名を読み取る場合、main()の代わりにwmain()を使用して引数をワイド文字列として取得できます。

関連する問題