2010-09-29 22 views
61

Có một câu hỏi thường gặp nhất, và vấn đề này là mơ hồ đối với tôi và vì tôi không biết nhiều về nó.Cách hiệu quả để tìm Mã hóa của bất kỳ tệp nào

Nhưng tôi muốn có cách rất chính xác để tìm tệp Encoding. Chính xác như Notepad ++.

+1

thể trùng lặp của [Java: Làm thế nào để xác định mã hóa charset đúng một dòng ] (http://stackoverflow.com/questions/499010/java-how-to-determine-the-correct-charset-encoding-of-a-stream) – Oded

+0

Mã hóa nào? UTF-8 so với UTF-16, lớn so với ít người dùng cuối? Hay bạn đang đề cập đến các mã MSDos cũ, chẳng hạn như shift-JIS hoặc Cyrillic, vv? – dthorpe

+0

Một bản sao có thể khác: http://stackoverflow.com/questions/436220/python-is-there-a-way-to-determine-the-encoding-of-text-file – Oded

Trả lời

96

Thuộc tính StreamReader.CurrentEncoding hiếm khi trả về mã hóa tệp văn bản chính xác cho tôi. Tôi đã có thành công lớn hơn xác định endianness của một tập tin, bằng cách phân tích dấu ấn thứ tự byte (BOM):

/// <summary> 
/// Determines a text file's encoding by analyzing its byte order mark (BOM). 
/// Defaults to ASCII when detection of the text file's endianness fails. 
/// </summary> 
/// <param name="filename">The text file to analyze.</param> 
/// <returns>The detected encoding.</returns> 
public static Encoding GetEncoding(string filename) 
{ 
    // Read the BOM 
    var bom = new byte[4]; 
    using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read)) 
    { 
     file.Read(bom, 0, 4); 
    } 

    // Analyze the BOM 
    if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7; 
    if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8; 
    if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE 
    if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE 
    if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32; 
    return Encoding.ASCII; 
} 

Như một mặt lưu ý, bạn có thể muốn thay đổi dòng cuối cùng của phương pháp này để trở Encoding.Default thay thế, do mã hóa cho trang mã ANSI hiện tại của hệ điều hành được trả về theo mặc định.

+3

+1. Điều này làm việc cho tôi quá (trong khi detectEncodingFromByteOrderMarks không). Tôi đã sử dụng "FileStream mới (tên tệp, FileMode.Open, FileAccess.Read)" để tránh một IOException vì tệp chỉ đọc. – Polyfun

+1

điều này chắc chắn là câu trả lời đúng, câu trả lời chính xác không hoạt động đối với tôi – sebagomez

+26

Các tệp UTF-8 có thể không có BOM, trong trường hợp này nó sẽ trả lại ASCII không chính xác. – user626528

8

tôi muốn thử các bước sau:

1) Kiểm tra nếu có một Byte Order Mark

2) Kiểm tra xem tập tin có giá trị UTF8

3) Sử dụng các địa phương "ANSI "codepage (ANSI như Microsoft định nghĩa nó)

Bước 2 hoạt động vì hầu hết các chuỗi không ASCII trong các mã khác mà UTF8 không hợp lệ UTF8.

+0

Điều này có vẻ giống như câu trả lời đúng hơn, vì câu trả lời khác không phù hợp với tôi. Người ta có thể làm điều đó với File.OpenRead và .Read-ing vài byte đầu tiên của tập tin. – user420667

+0

Bước 2 là một bó toàn bộ công việc lập trình để kiểm tra các mẫu bit. – Nyerguds

+0

@Nyerguds Cách tiếp cận lười biếng là cố phân tích cú pháp dưới dạng UTF-8 và khởi động lại từ đầu khi bạn gặp lỗi giải mã. Một chút xấu xí (ngoại lệ cho luồng điều khiển) và tất nhiên việc phân tích cú pháp cần phải có tác dụng phụ miễn phí. – CodesInChaos

29

Các mã sau hoạt động tốt đối với tôi, bằng cách sử dụng lớp StreamReader:

using (var reader = new StreamReader(fileName, defaultEncodingIfNoBom, true)) 
    { 
     reader.Peek(); // you need this! 
     var encoding = reader.CurrentEncoding; 
    } 

Bí quyết là sử dụng Peek cuộc gọi, nếu không, .NET đã không được thực hiện bất cứ điều gì (và nó đã không đọc lời mở đầu , BOM). Tất nhiên, nếu bạn sử dụng bất kỳ cuộc gọi nào khác ReadXXX trước khi kiểm tra mã hóa, nó cũng hoạt động.

Nếu tệp không có BOM, khi đó mã hóa defaultEncodingIfNoBom sẽ được sử dụng. Ngoài ra còn có một StreamReader mà không có phương pháp này quá tải (trong trường hợp này, mặc định (ANSI) mã hóa sẽ được sử dụng như defaultEncodingIfNoBom), nhưng tôi recommand để xác định những gì bạn xem xét mã hóa mặc định trong bối cảnh của bạn.

Tôi đã thử nghiệm thành công với các tệp có BOM cho UTF8, UTF16/Unicode (LE & BE) và UTF32 (LE & BE). Nó không hoạt động đối với UTF7.

+0

Tôi lấy lại những gì được đặt làm mã hóa mặc định. Tôi có thể bị mất một cái gì đó? – Rama

+1

@DRAM - điều này có thể xảy ra nếu tệp không có BOM –

+0

Cảm ơn @Simon Mourier. Tôi dint mong đợi pdf của tôi/bất kỳ tập tin sẽ không có bom. Liên kết này http://stackoverflow.com/questions/4520184/how-to-detect-the-character-encoding-of-a-text-file có thể hữu ích cho những người cố gắng phát hiện mà không cần bom. – Rama

1

Nhìn vào đây để C#

https://msdn.microsoft.com/en-us/library/system.io.streamreader.currentencoding%28v=vs.110%29.aspx

string path = @"path\to\your\file.ext"; 

using (StreamReader sr = new StreamReader(path, true)) 
{ 
    while (sr.Peek() >= 0) 
    { 
     Console.Write((char)sr.Read()); 
    } 

    //Test for the encoding after reading, or at least 
    //after the first read. 
    Console.WriteLine("The encoding used was {0}.", sr.CurrentEncoding); 
    Console.ReadLine(); 
    Console.WriteLine(); 
} 
1

Các mã sau đây là mã Powershell của tôi để quy nếu một số cpp hoặc h hoặc ml tập tin được encodeding với tiêu chuẩn ISO-8859-1 (Latin-1) hoặc UTF-8 không có BOM, nếu không thì giả sử nó là GB18030. Tôi là một người Trung Quốc làm việc tại Pháp và MSVC tiết kiệm như Latin-1 trên máy tính Pháp và tiết kiệm như GB trên máy tính Trung Quốc, điều này giúp tôi tránh được vấn đề khi trao đổi tập tin nguồn giữa hệ thống và đồng nghiệp của tôi.

Cách đơn giản, nếu tất cả ký tự nằm giữa x00-x7E, ASCII, UTF-8 và Latin-1 đều giống nhau, nhưng nếu tôi đọc tệp không phải ASCII bằng UTF-8, chúng tôi sẽ tìm ký tự hiển thị, vì vậy hãy thử đọc bằng Latin-1.Trong tiếng Latin-1, giữa \ x7F và \ xAF trống, trong khi GB sử dụng đầy đủ giữa x00-xFF vì vậy nếu tôi có bất kỳ giữa hai, nó không phải là Latin-1

Mã được viết bằng PowerShell nhưng sử dụng. để dễ dàng dịch sang C# hoặc F #

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False) 
foreach($i in Get-ChildItem .\ -Recurse -include *.cpp,*.h, *.ml) { 
    $openUTF = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::UTF8) 
    $contentUTF = $openUTF.ReadToEnd() 
    [regex]$regex = '�' 
    $c=$regex.Matches($contentUTF).count 
    $openUTF.Close() 
    if ($c -ne 0) { 
     $openLatin1 = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('ISO-8859-1')) 
     $contentLatin1 = $openLatin1.ReadToEnd() 
     $openLatin1.Close() 
     [regex]$regex = '[\x7F-\xAF]' 
     $c=$regex.Matches($contentLatin1).count 
     if ($c -eq 0) { 
      [System.IO.File]::WriteAllLines($i, $contentLatin1, $Utf8NoBomEncoding) 
      $i.FullName 
     } 
     else { 
      $openGB = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('GB18030')) 
      $contentGB = $openGB.ReadToEnd() 
      $openGB.Close() 
      [System.IO.File]::WriteAllLines($i, $contentGB, $Utf8NoBomEncoding) 
      $i.FullName 
     } 
    } 
} 
Write-Host -NoNewLine 'Press any key to continue...'; 
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown'); 
1

Kiểm tra điều này.

UDE

Đây là một cổng của Mozilla phổ Charset Detector và bạn có thể sử dụng nó như thế này ...

public static void Main(String[] args) 
{ 
    string filename = args[0]; 
    using (FileStream fs = File.OpenRead(filename)) { 
     Ude.CharsetDetector cdet = new Ude.CharsetDetector(); 
     cdet.Feed(fs); 
     cdet.DataEnd(); 
     if (cdet.Charset != null) { 
      Console.WriteLine("Charset: {0}, confidence: {1}", 
       cdet.Charset, cdet.Confidence); 
     } else { 
      Console.WriteLine("Detection failed."); 
     } 
    } 
} 
+0

Bạn nên biết rằng UDE là GPL – lindexi

+0

Ok nếu bạn lo lắng về giấy phép thì bạn có thể sử dụng giấy phép này. Được cấp phép là MIT và bạn có thể sử dụng nó cho cả phần mềm nguồn mở và phần mềm nguồn đóng. https://www.nuget.org/packages/SimpleHelpers.FileEncoding/ –

+0

Thx, có vẻ như nó có thể hiệu quả với tôi. – lindexi

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