2009-01-26 19 views
21

Tôi đang cố gắng viết một hàm thành viên tĩnh trong C# hoặc tìm một trong .NET Framework sẽ tái xử lý đường dẫn tệp tới hệ thống tệp chỉ định.C# Filepath Recasing

Ví dụ:

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 

Tôi đã thử đoạn mã sau đây và nhiều biến thể của nó và nó vẫn không hoạt động. Tôi biết Windows không phân biệt chữ hoa chữ thường nhưng tôi cần phải chuyển các đường dẫn tệp này đến ClearCase, xem xét vỏ đường dẫn tệp vì nó là ứng dụng Unix và 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; 
} 
+0

Do ClearCase. Tôi đã nói điều đó trong câu hỏi. –

Trả lời

21

Đây là một thực hiện khá đơn giản mà giả định rằng các tập tin và thư mục tất cả các tồn tại và có thể truy cập:

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

Có một lỗi với điều này, mặc dù: đường dẫn tương đối được chuyển đổi thành đường dẫn tuyệt đối. Mã ban đầu của bạn ở trên đã làm như vậy, vì vậy tôi giả sử rằng bạn muốn hành vi này.

+0

Điều này không may trên đường dẫn UNC. Tôi cần nó để làm việc trên đường dẫn UNC. Giống như \\ SERVERNAME \ Hostdir \ MyDocument.docx –

+0

Tôi sẽ đặt câu trả lời này là câu trả lời. Đối với nhu cầu của tôi, nó hoạt động tốt nhất. Tôi có thể bổ sung thêm hack trên đầu trang của hack này để làm cho nó hoạt động nhưng nó quay ra tôi đang rời khỏi tính năng ra vì biến chứng. –

+2

Tôi tìm thấy 'dirInfo.Name' chỉ đơn giản là sai đối với cổ phiếu UNC, bởi vì nó giảm tên máy chủ. Với mục đích của tôi, 'dirInfo.FullName.ToUpperInvariant()' là đủ tốt - nó không phục hồi đúng trường hợp cho tên chia sẻ, nhưng nó xây dựng một đường dẫn hợp lệ. – Weeble

1

Bạn có thể tìm kiếm tệp mà bạn muốn đặt trường hợp và trả về kết quả tìm kiếm của mình (bạn muốn kiểm tra vỏ của tệp tồn tại, phải không?). Một cái gì đó như thế này:

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

Đây có phải là những gì bạn đang tìm kiếm không?

+0

Trường hợp sẽ chỉ có ở đó nếu tệp tồn tại. Nếu không thì bạn không nghĩ sao? – manojlds

+0

Thao tác này sẽ khắc phục sự cố của tệp, nhưng toàn bộ phần còn lại của đường dẫn vẫn không đúng cách. – PolyTekPatrick

1

Tôi có một cái gì đó hiệu quả hơn nhưng:

1) Dường như nó không hoạt động đối với mọi trường hợp. (Tôi đã không tìm ra mô hình của các tập tin và thư mục nào mà nó chính xác nhận được vỏ bọc, và cái nào nó không có.)

2) Đó là Windows cụ thể.

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

Dưới đây hoạt động tốt ở mức độ mà tôi đã thử nghiệm ... chỉ bắt được là API được sử dụng chỉ có sẵn trong 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); 
+1

Giải pháp tuyệt vời cho Vista. Cẩn thận rằng điều này giải quyết các liên kết tượng trưng. Xem nhận xét tại: http://msdn.microsoft.com/en-us/library/aa364962(VS.85).aspx – Ants

1

Câu trả lời bởi @Ants trên nên hoàn toàn nhận được tín là câu trả lời chấp nhận. Tuy nhiên, tôi đã tái cấu trúc nó một chút với mục đích của mình. Cách tiếp cận này được đóng gói như các phương thức mở rộng cho FileInfo và DirectoryInfo, và cũng trả về các phương thức được sửa chữa.

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

Tôi đã đập đầu về một số vấn đề không thống nhất trong trường hợp với FileInfo. Để đảm bảo tính chắc chắn, tôi chuyển đổi thành tất cả các mũ khi thực hiện so sánh hoặc lưu trữ các đường dẫn. Để làm rõ mục đích của mã, tôi cũng có các phương pháp mở rộng này:

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

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

Bạn sẽ muốn hệ thống tìm tệp cho bạn. Tôi làm điều này bằng cách giả vờ rằng tôi không biết đường dẫn chính xác, tức là có hệ thống tìm kiếm:

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

Vì vậy, chúng tôi tìm kiếm trong thư mục, lọc vào tên tập tin chính xác và hạn chế việc tìm kiếm vào thư mục hiện chỉ (không đệ quy).

Điều này trả về một mảng chuỗi chứa đường dẫn tệp đơn với vỏ chính xác (nếu tệp tồn tại) hoặc không có gì (nếu tệp không tồn tại).

Một cảnh báo: Bạn có thể cần phải không cho phép ký tự đại diện trong đường dẫn nhập, vì cách tiếp cận này chấp nhận và có thể tìm thấy nhiều tệp.

Sửa

Các ký tự ổ đĩa dường như vẫn theo vỏ mà chúng tôi cung cấp. Ngoài ra, điều này cần phải được kiểm tra cho các đường dẫn UNC.

Các vấn đề liên quan