Pergunta

Eu estou tentando escrever uma função membro estático em C # ou encontrar um no .NET Framework que irá re-caso um caminho de arquivo ao que especifica sistema de arquivos.

Exemplo:

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

Eu tentei o seguinte código abaixo e muitas variantes do mesmo e ele ainda não funciona. Eu sei que o Windows é case-insensitive em geral, mas eu preciso passar esses caminhos de arquivo para ClearCase que considera caixa caminho do arquivo, já que é uma aplicação 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;
}
Foi útil?

Solução

Esta é uma aplicação muito simples que assume que o arquivo e diretórios todos existem e são acessíveis:

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

Há um bug com isso, porém: Os caminhos relativos são convertidos em caminhos absolutos. Seu código original acima fez o mesmo, então eu estou supondo que você quer esse comportamento.

Outras dicas

A seguir funciona bem, na medida em que eu testei ... único problema é que a API usado está disponível apenas no 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);

Você pode procurar o arquivo que você deseja obter o caso sobre e retornar os resultados de sua pesquisa (você quiser verificar o invólucro de um arquivo que existe, certo?). Algo parecido com isto:

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

É isso que você está procurando?

Eu tenho algo mais eficiente, mas:

1) Não parece ao trabalho para todos os casos. (Eu não descobri o padrão de quais arquivos e diretórios que recebe correctamente o invólucro, e quais não.)

2) é específico do 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);

A resposta por @Ants acima deve absolutamente obter crédito como a resposta aceita. No entanto, eu reformulado-lo um pouco para os meus propósitos. A abordagem é empacotado como métodos de extensão para FileInfo e DirectoryInfo, e retorno corrigido queridos também.

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

Eu estive batendo a cabeça sobre algumas questões caso de inconsistência com FileInfo. A fim de garantir robustez, eu converter para todos os tampões ao fazer a comparação ou armazenamento dos caminhos. Para esclarecer a intenção do código, eu também tenho esses métodos de extensão:

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

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

Você deseja que o sistema para localizar o arquivo para você. Eu faço isso fingindo que eu não sei o caminho exato, ou seja, ter o sistema procurar :

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

Por isso, procurar no diretório, filtrando o nome exato do arquivo e limitar a busca para o diretório atual apenas (sem recursão).

Isso retorna uma matriz de cadeia contendo quer o caminho único ficheiro com invólucro correcto (se existir o ficheiro) ou nada (se o ficheiro não existe).

Um aviso:. Você pode precisar para não permitir wildcards no caminho de entrada, porque esta abordagem aceita-los e pode encontrar vários arquivos como resultado

Editar

A letra da unidade parece ainda seguem o invólucro que nós fornecemos. Além disso, isso precisa ser testado para caminhos UNC.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top