21

C# で静的メンバー関数を記述しようとしているか、.NET Framework で、ファイル システムが指定するファイル パスをリケースする関数を見つけようとしています。

例:

string filepath = @"C:\temp.txt";
filepath = FileUtility.RecaseFilepath(filepath);

// filepath = C:\Temp.TXT
// Where the real fully qualified filepath in the NTFS volume is C:\Temp.TXT

以下のコードとその多くのバリエーションを試しましたが、まだ機能しません。一般に、Windows では大文字と小文字が区別されないことはわかっていますが、これらのファイル パスを ClearCase に渡す必要があります。ClearCase は Unix および Windows アプリケーションであるため、ファイル パスの大文字と小文字を区別します。

public static string GetProperFilePathCapitalization(string filepath)
{
    string result = "";

    try
    {
        result = Path.GetFullPath(filepath);
        DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(result));
        FileInfo[] fi = dir.GetFiles(Path.GetFileName(result));
        if (fi.Length > 0)
        {
            result = fi[0].FullName;
        }
    }
    catch (Exception)
    {
        result = filepath;
    }

    return result;
}
4

6 に答える 6

23

これは、ファイルとディレクトリがすべて存在し、アクセス可能であることを前提とした非常に単純な実装です。

static string GetProperDirectoryCapitalization(DirectoryInfo dirInfo)
{
    DirectoryInfo parentDirInfo = dirInfo.Parent;
    if (null == parentDirInfo)
        return dirInfo.Name;
    return Path.Combine(GetProperDirectoryCapitalization(parentDirInfo),
                        parentDirInfo.GetDirectories(dirInfo.Name)[0].Name);
}

static string GetProperFilePathCapitalization(string filename)
{
    FileInfo fileInfo = new FileInfo(filename);
    DirectoryInfo dirInfo = fileInfo.Directory;
    return Path.Combine(GetProperDirectoryCapitalization(dirInfo),
                        dirInfo.GetFiles(fileInfo.Name)[0].Name);
}

ただし、これにはバグがあります。相対パスが絶対パスに変換されます。上記の元のコードは同じことをしたので、この動作が必要だと思います。

于 2009-01-26T09:12:09.740 に答える
3

以下は、私がテストした範囲で問題なく動作します...唯一の問題は、使用されている API が Vista でのみ使用できることです。

static void Main(string[] args)
{
    using (FileStream fs = File.OpenRead(@"D:\temp\case\mytest.txt"))
    {
        StringBuilder path = new StringBuilder(512);
        GetFinalPathNameByHandle(fs.SafeFileHandle.DangerousGetHandle(), path, path.Capacity, 0);
        Console.WriteLine(path.ToString());
    }
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern int GetFinalPathNameByHandle(IntPtr handle, [In, Out] StringBuilder path, int bufLen, int flags);
于 2009-01-28T12:13:28.423 に答える
1

私はもっ​​と効率的なものを持っていますが:

1)すべての場合に機能するとは限りません。(どのファイルとディレクトリが正しく大文字と小文字を区別し、どのファイルとディレクトリが大文字と小文字を区別しないかはわかりません。)

2)Windows固有です。

static string GetProperFilePathCapitalization1(string filename)
{
    StringBuilder sb = new StringBuilder(260);
    int length = GetLongPathName(filename, sb, sb.Capacity);

    if (length > sb.Capacity)
    {
        sb.Capacity = length;
        length = GetLongPathName(filename, sb, sb.Capacity);
    }

    if (0 == length)
        throw new Win32Exception("GetLongPathName");

    return sb.ToString();
}

[DllImport("kernel32.dll")]
static extern int GetLongPathName(string path, StringBuilder pszPath, int cchPath);
于 2009-01-28T07:19:45.880 に答える
1

上記の@Antsによる回答は、受け入れられた回答として絶対に認められるはずです。ただし、目的に合わせて少しリファクタリングしました。このアプローチは、FileInfo および DirectoryInfo の拡張メソッドとしてパッケージ化されており、修正されたものも返します。

public static DirectoryInfo GetProperCasedDirectoryInfo(this DirectoryInfo dirInfo)
{
    // Inspired by http://stackoverflow.com/a/479198/244342

    if (!dirInfo.Exists)
    {
        // Will not be able to match filesystem
        return dirInfo;
    }

    DirectoryInfo parentDirInfo = dirInfo.Parent;
    if (parentDirInfo == null)
    {
        return dirInfo;
    }
    else
    {
        return parentDirInfo.GetProperCasedDirectoryInfo().GetDirectories(dirInfo.Name)[0];
    }
}

public static FileInfo GetProperCasedFileInfo(this FileInfo fileInfo)
{
    // Inspired by http://stackoverflow.com/a/479198/244342

    if (!fileInfo.Exists)
    {
        // Will not be able to match filesystem
        return fileInfo;
    }

    return fileInfo.Directory.GetProperCasedDirectoryInfo().GetFiles(fileInfo.Name)[0];
}

私は、FileInfo の大文字と小文字の不一致の問題について頭を悩ませてきました。堅牢性を確保するために、パスの比較または保存を行うときにすべて大文字に変換します。コードの意図を明確にするために、次の拡張メソッドもあります。

public static string GetPathForKey(this FileInfo File)
{
    return File.FullName.ToUpperInvariant();
}

public static string GetDirectoryForKey(this FileInfo File)
{
    return File.DirectoryName.ToUpperInvariant();
}
于 2012-08-07T22:20:04.297 に答える
1

ケースを取得したいファイルを検索し、検索結果を返すことができます (存在するファイルのケースをチェックしたいでしょう?)。このようなもの:

public static string GetProperFilePathCapitalization(string filepath) {
   string directoryPath = Path.GetDirectoryName(filepath);
   string[] files = Directory.GetFiles(directoryPath, Path.GetFileName(filepath));
   return files[0];
}

これはあなたが探しているものですか?

于 2009-01-26T04:53:41.247 に答える
0

システムにファイルを見つけてもらいたいでしょう。正確なパスがわからないふりをしてこれを行います。つまり、システム検索を行います。

var fileName = Path.GetFileName(filePath);
var dir = Path.GetDirectoryName(filePath);
var filePaths = Directory.GetFiles(dir, fileName, SearchOption.TopDirectoryOnly);
var caseCorrectedFilePath = filePaths.FirstOrDefault();

そのため、ディレクトリ内を検索し、正確なファイル名でフィルタリングし、検索を現在のディレクトリのみに制限します (再帰は行いません)。

これは、大文字と小文字が正しい単一のファイル パス (ファイルが存在する場合) または何も含まれない (ファイルが存在しない場合) のいずれかを含む文字列配列を返します。

1 つの警告: 入力パスでワイルドカードを許可しないようにする必要がある場合があります。

編集

ドライブ文字は、提供されている大文字と小文字の区別に従っているようです。また、これは UNC パスに対してテストする必要があります。

于 2015-11-04T10:29:31.850 に答える