Domanda

Sto provando a scrivere una funzione membro statica in C # o trovarne una in .NET Framework che ricollegherà un percorso di file a ciò che il filesystem specifica.

Esempio:

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

Ho provato il seguente codice di seguito e molte varianti di esso e ancora non funziona. So che Windows non fa distinzione tra maiuscole e minuscole in generale, ma ho bisogno di passare questi percorsi di file a ClearCase che considera l'instradamento del percorso dei file poiché è un'applicazione Unix e 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;
}
È stato utile?

Soluzione

Questa è un'implementazione piuttosto semplice che presuppone che il file e le directory esistano e siano accessibili:

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

Tuttavia, esiste un bug con questo: i percorsi relativi vengono convertiti in percorsi assoluti. Il tuo codice originale sopra ha fatto lo stesso, quindi presumo che tu voglia questo comportamento.

Altri suggerimenti

Quanto segue funziona benissimo nella misura in cui ho testato ... solo il problema è che l'API utilizzata è disponibile solo in 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);

È possibile cercare il file su cui si desidera ottenere il caso e restituire i risultati della ricerca (si desidera controllare il case di un file esistente, giusto?). Qualcosa del genere:

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

È questo quello che stai cercando?

Ho qualcosa di più efficiente ma:

1) Non sembra funzionare in tutti i casi. (Non ho capito il modello di quali file e directory ottiene correttamente il case, e quali no.)

2) È specifico di 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 risposta di @Ants sopra dovrebbe assolutamente ottenere credito come risposta accettata. Tuttavia, l'ho riformulato un po 'per i miei scopi. L'approccio è impacchettato come metodi di estensione per FileInfo e DirectoryInfo e restituisce anche quelli corretti.

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

Mi sono sbattuto la testa per alcuni problemi di incoerenza tra maiuscole e minuscole con FileInfo. Al fine di garantire robustezza, durante il confronto o la memorizzazione dei percorsi, converto in maiuscolo. Per chiarire l'intento del codice, ho anche questi metodi di estensione:

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

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

Vorrai che il sistema trovi il file per te. Faccio questo fingendo di non conoscere il percorso esatto, ovvero avere il sistema cerca :

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

Quindi cerchiamo nella directory, filtrando il nome esatto del file e limitando la ricerca solo alla directory corrente (nessuna ricorsione).

Restituisce un array di stringhe contenente il percorso del singolo file con il case corretto (se il file esiste) o niente (se il file non esiste).

Un avvertimento: potrebbe essere necessario non consentire i caratteri jolly nel percorso di input, perché questo approccio li accetta e potrebbe trovare di conseguenza più file.

Modifica

La lettera di unità sembra seguire ancora l'involucro che forniamo. Inoltre, questo deve essere testato per i percorsi UNC.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top