Evet, en sık sorulan sorudur ve bu konu benim için belirsizdir ve bu konuda pek bir şey bilmediğim için.
Ama Kodlayan bir dosya bulmanın çok kesin bir yolunu istiyorum. Notepad ++ kadar hassas.
Evet, en sık sorulan sorudur ve bu konu benim için belirsizdir ve bu konuda pek bir şey bilmediğim için.
Ama Kodlayan bir dosya bulmanın çok kesin bir yolunu istiyorum. Notepad ++ kadar hassas.
Yanıtlar:
StreamReader.CurrentEncoding
Mülkiyet nadiren benim için kodlama doğru metin dosyası döndürür. Bayt sırası işaretini (BOM) analiz ederek bir dosyanın geçerliliğini belirlemede daha büyük başarı elde ettim. Dosyanın bir Malzeme Listesi yoksa, bu dosyanın kodlamasını belirleyemez.
* UTF-32LE algılamasını içerecek ve UTF-32BE için doğru kodlamayı döndürecek şekilde GÜNCELLENDİ 4/08/2020
/// <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 && bom[2] == 0 && bom[3] == 0) return Encoding.UTF32; //UTF-32LE
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 new UTF32Encoding(true, true); //UTF-32BE
// We actually have no idea what the encoding is if we reach this point, so
// you may wish to return null instead of defaulting to ASCII
return Encoding.ASCII;
}
StreamReader
, o uygulama daha fazla kişi isteyecektir şeydir. Mevcut Encoding.Unicode
nesneleri kullanmak yerine yeni kodlamalar yaparlar , bu nedenle eşitlik kontrolleri başarısız olur (bu durum nadiren gerçekleşebilir çünkü örneğin Encoding.UTF8
farklı nesneler döndürebilir), ancak (1) gerçekten tuhaf UTF-7 formatını kullanmaz, (2) BOM bulunmazsa varsayılan olarak UTF-8 olur ve (3) farklı bir varsayılan kodlama kullanmak için geçersiz kılınabilir.
00 00 FE FF
) tespit ettiğinizde, sistem tarafından sağlanan Encoding.UTF32
, küçük bir endian kodlaması olan ( burada belirtildiği gibi ) döndürürsünüz . Ayrıca, @Nyerguds tarafından belirtildiği gibi, imzası olan UTF32LE'yi hala aramıyorsunuz FF FE 00 00
( en.wikipedia.org/wiki/Byte_order_mark'a göre ). Bu kullanıcının da belirttiği gibi, alt toplama olduğu için, bu kontrol 2 baytlık kontrollerden önce yapılmalıdır.
Aşağıdaki kod, StreamReader
sınıfı kullanarak benim için iyi çalışıyor :
using (var reader = new StreamReader(fileName, defaultEncodingIfNoBom, true))
{
reader.Peek(); // you need this!
var encoding = reader.CurrentEncoding;
}
İşin püf noktası Peek
aramayı kullanmaktır , aksi takdirde .NET hiçbir şey yapmamıştır (ve başlangıç ekini, BOM'u okumamıştır). Elbette ReadXXX
, kodlamayı kontrol etmeden önce başka bir çağrı kullanırsanız , o da çalışır.
Dosyada BOM yoksa, defaultEncodingIfNoBom
kodlama kullanılacaktır. Bu aşırı yükleme yöntemine sahip olmayan bir StreamReader da vardır (bu durumda, Default (ANSI) kodlaması defaultEncodingIfNoBom olarak kullanılacaktır), ancak bağlamınızda varsayılan kodlamayı düşündüğünüz şeyi tanımlamanızı tavsiye ederim.
Bunu UTF8, UTF16 / Unicode (LE & BE) ve UTF32 (LE & BE) için BOM içeren dosyalarla başarıyla test ettim. UTF7 için çalışmaz.
foreach($filename in $args) { $reader = [System.IO.StreamReader]::new($filename, [System.Text.Encoding]::default,$true); $peek = $reader.Peek(); $reader.currentencoding | select bodyname,encodingname; $reader.close() }
UTF-8 without BOM
Aşağıdaki adımları deneyeceğim:
1) Bayt Sırası İşareti olup olmadığını kontrol edin
2) Dosyanın geçerli UTF8 olup olmadığını kontrol edin
3) Yerel "ANSI" kod sayfasını kullanın (Microsoft'un tanımladığı şekliyle ANSI)
Adım 2, UTF8'in geçerli UTF8 olmadığı kod sayfalarındaki ASCII olmayan dizilerin çoğu olduğu için çalışır.
Utf8Encoding
bir istisna atılıp atılmayacağını veya sessiz veri bozulmasını tercih edip etmediğinizi belirleyen fazladan bir parametre iletebilirsiniz.
Şuna göz at.
Bu, Mozilla Universal Charset Detector'ın bir limanıdır ve bu şekilde kullanabilirsiniz ...
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.");
}
}
}
The library is subject to the Mozilla Public License Version 1.1 (the "License"). Alternatively, it may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL").
@CodesInChaos tarafından önerilen adımlar için uygulama ayrıntılarını sağlamak:
1) Bayt Sırası İşareti olup olmadığını kontrol edin
2) Dosyanın geçerli UTF8 olup olmadığını kontrol edin
3) Yerel "ANSI" kod sayfasını kullanın (Microsoft'un tanımladığı şekliyle ANSI)
Adım 2, UTF8'in geçerli UTF8 olmadığı kod sayfalarındaki ASCII olmayan dizilerin çoğu olduğu için çalışır. https://stackoverflow.com/a/4522251/867248 taktiği daha ayrıntılı olarak açıklıyor.
using System; using System.IO; using System.Text;
// Using encoding from BOM or UTF8 if no BOM found,
// check if the file is valid, by reading all lines
// If decoding fails, use the local "ANSI" codepage
public string DetectFileEncoding(Stream fileStream)
{
var Utf8EncodingVerifier = Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback());
using (var reader = new StreamReader(fileStream, Utf8EncodingVerifier,
detectEncodingFromByteOrderMarks: true, leaveOpen: true, bufferSize: 1024))
{
string detectedEncoding;
try
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
}
detectedEncoding = reader.CurrentEncoding.BodyName;
}
catch (Exception e)
{
// Failed to decode the file using the BOM/UT8.
// Assume it's local ANSI
detectedEncoding = "ISO-8859-1";
}
// Rewind the stream
fileStream.Seek(0, SeekOrigin.Begin);
return detectedEncoding;
}
}
[Test]
public void Test1()
{
Stream fs = File.OpenRead(@".\TestData\TextFile_ansi.csv");
var detectedEncoding = DetectFileEncoding(fs);
using (var reader = new StreamReader(fs, Encoding.GetEncoding(detectedEncoding)))
{
// Consume your file
var line = reader.ReadLine();
...
reader.Peek()
bunun yerine kullanmayı tercih ederim while (!reader.EndOfStream) { var line = reader.ReadLine(); }
reader.Peek()
akışın tamamını okumaz. Daha büyük akışlarda Peek()
yetersiz olduğunu buldum . Onun reader.ReadToEndAsync()
yerine kullandım .
var Utf8EncodingVerifier = Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback());
kullanılır try
. Kodlayıcı sağlanan metni ayrıştıramazsa (metin utf8 ile kodlanmamışsa), Utf8EncodingVerifier atacaktır. İstisna yakalandı ve sonra metnin utf8 olmadığını ve varsayılan olarak ISO-8859-1 olduğunu biliyoruz
Aşağıdaki kodlar, bazı cpp veya h veya ml dosyalarının ISO-8859-1 (Latin-1) veya UTF-8 ile BOM olmadan kodlanıp kodlanmadığını belirlemek için kullandığım Powershell kodlarımdır, eğer ikisinin de GB18030 olduğunu varsaymayın. Ben Fransa'da çalışan bir Çinliyim ve MSVC Fransız bilgisayarına Latin-1 olarak kaydediyor ve Çin bilgisayarına GB olarak kaydediyor, bu da sistemim ve meslektaşlarım arasında kaynak dosya alışverişi yaparken kodlama sorununu önlememe yardımcı oluyor.
Yol basit, eğer tüm karakterler x00-x7E arasındaysa, ASCII, UTF-8 ve Latin-1 hepsi aynıysa, ancak UTF-8 ile ASCII olmayan bir dosya okursam, special özel karakterini bulacağız , bu yüzden Latin-1 ile okumaya çalışın. Latin-1'de \ x7F ile \ xAF arası boştur, GB x00-xFF arasında full kullanır, bu yüzden ikisi arasında bir tane varsa, Latin-1 değildir.
Kod PowerShell'de yazılmıştır, ancak .net kullanır, bu nedenle C # veya F # 'a çevrilmesi kolaydır
$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');
.NET pek yararlı değildir, ancak aşağıdaki algoritmayı deneyebilirsiniz:
İşte çağrı:
var encoding = FileHelper.GetEncoding(filePath);
if (encoding == null)
throw new Exception("The file encoding is not supported. Please choose one of the following encodings: UTF8/UTF7/iso-8859-1");
İşte kod:
public class FileHelper
{
/// <summary>
/// Determines a text file's encoding by analyzing its byte order mark (BOM) and if not found try parsing into diferent encodings
/// Defaults to UTF8 when detection of the text file's endianness fails.
/// </summary>
/// <param name="filename">The text file to analyze.</param>
/// <returns>The detected encoding or null.</returns>
public static Encoding GetEncoding(string filename)
{
var encodingByBOM = GetEncodingByBOM(filename);
if (encodingByBOM != null)
return encodingByBOM;
// BOM not found :(, so try to parse characters into several encodings
var encodingByParsingUTF8 = GetEncodingByParsing(filename, Encoding.UTF8);
if (encodingByParsingUTF8 != null)
return encodingByParsingUTF8;
var encodingByParsingLatin1 = GetEncodingByParsing(filename, Encoding.GetEncoding("iso-8859-1"));
if (encodingByParsingLatin1 != null)
return encodingByParsingLatin1;
var encodingByParsingUTF7 = GetEncodingByParsing(filename, Encoding.UTF7);
if (encodingByParsingUTF7 != null)
return encodingByParsingUTF7;
return null; // no encoding found
}
/// <summary>
/// Determines a text file's encoding by analyzing its byte order mark (BOM)
/// </summary>
/// <param name="filename">The text file to analyze.</param>
/// <returns>The detected encoding.</returns>
private static Encoding GetEncodingByBOM(string filename)
{
// Read the BOM
var byteOrderMark = new byte[4];
using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
file.Read(byteOrderMark, 0, 4);
}
// Analyze the BOM
if (byteOrderMark[0] == 0x2b && byteOrderMark[1] == 0x2f && byteOrderMark[2] == 0x76) return Encoding.UTF7;
if (byteOrderMark[0] == 0xef && byteOrderMark[1] == 0xbb && byteOrderMark[2] == 0xbf) return Encoding.UTF8;
if (byteOrderMark[0] == 0xff && byteOrderMark[1] == 0xfe) return Encoding.Unicode; //UTF-16LE
if (byteOrderMark[0] == 0xfe && byteOrderMark[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE
if (byteOrderMark[0] == 0 && byteOrderMark[1] == 0 && byteOrderMark[2] == 0xfe && byteOrderMark[3] == 0xff) return Encoding.UTF32;
return null; // no BOM found
}
private static Encoding GetEncodingByParsing(string filename, Encoding encoding)
{
var encodingVerifier = Encoding.GetEncoding(encoding.BodyName, new EncoderExceptionFallback(), new DecoderExceptionFallback());
try
{
using (var textReader = new StreamReader(filename, encodingVerifier, detectEncodingFromByteOrderMarks: true))
{
while (!textReader.EndOfStream)
{
textReader.ReadLine(); // in order to increment the stream position
}
// all text parsed ok
return textReader.CurrentEncoding;
}
}
catch (Exception ex) { }
return null; //
}
}
C # için buraya bak
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();
}