Question

J'essaie d'écrire une fonction membre statique en C # ou d'en trouver une dans le .NET Framework qui re-casse un chemin d'accès au fichier spécifié par le système de fichiers.

Exemple:

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

J'ai essayé le code suivant ci-dessous et de nombreuses variantes et il ne fonctionne toujours pas. Je sais que Windows ne fait généralement pas la distinction entre les majuscules et les minuscules, mais je dois transmettre ces chemins de fichiers à ClearCase, qui considère le casier des chemins de fichiers car il s’agit d’une application Unix et 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;
}
Était-ce utile?

La solution

Ceci est une implémentation assez simple qui suppose que le fichier et les répertoires existent et sont tous accessibles:

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);
}

Il y a cependant un bogue avec ceci: Les chemins relatifs sont convertis en chemins absolus. Votre code original ci-dessus a fait de même, alors je suppose que vous voulez ce comportement.

Autres conseils

Les éléments ci-dessous fonctionnent correctement dans la mesure où j'ai effectué les tests. Le seul problème est que l'API utilisée n'est disponible que sous 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);

Vous pouvez rechercher le fichier pour lequel vous souhaitez obtenir l’affaire et renvoyer les résultats de votre recherche (vous souhaitez vérifier la casse d’un fichier existant, non?). Quelque chose comme ça:

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

Est-ce ce que vous cherchez?

J'ai quelque chose de plus efficace mais:

1) Cela ne semble pas fonctionner dans tous les cas. (Je n'ai pas encore déterminé quels modèles de fichiers et de répertoires il récupère correctement, ni ceux qu'il ne contient pas.)

2) C’est spécifique à 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);

La réponse de @Ants ci-dessus doit absolument obtenir un crédit en tant que réponse acceptée. Cependant, je l'ai refactorisé un peu à mes fins. Cette approche est présentée sous forme de méthodes d’extension pour FileInfo et DirectoryInfo, mais renvoie également les méthodes corrigées.

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];
}

Je me suis cogné la tête à propos de problèmes de cohérence de cas avec FileInfo. Afin de garantir la robustesse, je convertis en majuscules lors de la comparaison ou du stockage des chemins. Pour clarifier l’intention du code, j’ai également ces méthodes d’extension:

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

public static string GetDirectoryForKey(this FileInfo File)
{
    return File.DirectoryName.ToUpperInvariant();
}

Vous souhaiterez que le système trouve le fichier pour vous. Je fais cela en faisant semblant de ne pas connaître le chemin exact, c’est-à-dire que le système recherche :

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

Nous recherchons donc dans le répertoire, en filtrant le nom de fichier exact et en limitant la recherche au répertoire actuel uniquement (pas de récursivité).

Ceci retourne un tableau de chaînes contenant soit le chemin d'accès unique au fichier avec la casse correcte (si le fichier existe) ou rien (si le fichier n'existe pas).

Un avertissement: il se peut que vous deviez interdire les caractères génériques dans le chemin d'entrée, car cette approche les accepte et peut par conséquent permettre de rechercher plusieurs fichiers.

Modifier

La lettre de lecteur semble toujours suivre le boîtier fourni. De plus, cela doit être testé pour les chemins UNC.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top