[英]How do I convert from a possibly Windows 1252 'ANSI' encoded uploaded file to UTF8 in .NET?
[英]Convert ANSI (Windows 1252) to UTF8 in C#
我之前在 Stack Overflow 上以一種迂回的方式問過這個問題,這次想把它做對。 如何將 ANSI(代碼頁 1252)轉換為 UTF-8,同時保留特殊字符? (我知道 UTF-8 支持比 ANSI 更大的字符集,但是如果我可以保留 ANSI 支持的所有 UTF-8 字符並將其余字符替換為?
或其他東西,那也沒關系)
為什么我要轉換 ANSI → UTF-8
我基本上正在編寫一個程序,將 vCard 文件 (VCF) 拆分為單個文件,每個文件包含一個聯系人。 我注意到諾基亞和索尼愛立信手機以 UTF-8(無 BOM)格式保存備份 VCF 文件,但 Android 以 ANSI (1252) 格式保存它。 天知道其他手機以什么格式保存它們!
所以我的問題是
tl;dr需要知道如何將字符編碼從 (ANSI / UTF8) 轉換為 (UTF8 / ANSI),同時保留所有特殊字符。
您不應該從一種編碼轉換為另一種編碼。 您必須使用創建文件時使用的編碼來讀取每個文件,否則您將丟失信息。
使用正確的編碼讀取文件后,您將獲得 Unicode 字符串形式的內容,然后您可以使用您喜歡的任何編碼保存它。
如果需要檢測編碼,可以將文件作為字節讀取,然后查找特定於任一編碼的字符代碼。 如果文件不包含特殊字符,則任一編碼都將起作用,因為這兩種編碼的字符 32..127 相同。
按照第 3.4 章中的規范要求,VCF 以 utf-8 編碼。 你需要認真對待這一點,如果不是一成不變的,這種格式將毫無用處。 如果您看到某些 Android 應用程序對重音字符進行了重整,請假設這是該應用程序中的錯誤。 或者更有可能的是,它從其他地方獲得了錯誤信息。 您嘗試更正編碼會導致更多問題,因為您的卡版本永遠不會與原始卡匹配。
您使用 Encoding.GetEncoding(1252).GetString() 從 1252 轉換為 utf-8,傳入一個byte[] 。 永遠不要試圖讀取一個字符串,它敲敲罷了到一個字節寫入代碼[]所以你可以使用的轉換方法,只是使編碼問題變得更糟。 換句話說,您需要使用 FileStream 而不是 StreamReader 讀取文件。 但同樣,避免解決其他人的問題。
這是我在 C# 中使用的(我一直在使用它從 Windows-1252 轉換為 UTF8)
public static String readFileAsUtf8(string fileName)
{
Encoding encoding = Encoding.Default;
String original = String.Empty;
using (StreamReader sr = new StreamReader(fileName, Encoding.Default))
{
original = sr.ReadToEnd();
encoding = sr.CurrentEncoding;
sr.Close();
}
if (encoding == Encoding.UTF8)
return original;
byte[] encBytes = encoding.GetBytes(original);
byte[] utf8Bytes = Encoding.Convert(encoding, Encoding.UTF8, encBytes);
return Encoding.UTF8.GetString(utf8Bytes);
}
我這樣做:
private static void ConvertAnsiToUTF8(string inputFilePath, string outputFilePath)
{
string fileContent = File.ReadAllText(inputFilePath, Encoding.Default);
File.WriteAllText(outputFilePath, fileContent, Encoding.UTF8);
}
我在將大量古代文本文件處理成格式良好的 PDF 時發現了這個問題。 所有文件都沒有 BOM,並且最舊的文件包含導致錯誤解碼為 UTF8 的代碼頁 1252 代碼點。 這只發生在某些時候,UTF8 大部分時間都在工作。 此外,最新的文本數據確實包含 UTF8 代碼點,所以它是一個混合包。
因此,我還設置了“檢測輸入文件具有哪種編碼”並閱讀了如何檢測文本文件的字符編碼? 以及如何確定文本的編碼? 得出的結論是,這充其量是困難的。
但是,我在評論中找到了每個軟件開發人員絕對必須了解 Unicode 和字符集的絕對最小值,閱讀它,並找到了這個寶石:
UTF-8 有一個巧妙的副作用,即英語文本在 UTF-8 中看起來與在 ASCII 中完全相同,因此美國人甚至不會注意到任何錯誤。 只有世界其他地方必須跳過箍。 具體來說,你好,即 U+0048 U+0065 U+006C U+006C U+006F,將存儲為 48 65 6C 6C 6F,看哪! 與存儲在 ASCII、ANSI 和地球上的每個 OEM 字符集相同。
整篇文章很短,值得一讀。
所以,我用下面的代碼解決了我的問題。 由於我的文本數據中只有少量包含困難的字符代碼點,因此我不介意異常處理的性能開銷,特別是因為這只需要運行一次。 也許有更聰明的方法可以避免try/catch
但我沒有費心設計一個。
public static string ReadAllTextFromFile(string file)
{
const int WindowsCodepage1252 = 1252;
string text;
try
{
var utf8Encoding = Encoding.GetEncoding("UTF-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
text = File.ReadAllText(file, utf8Encoding);
}
catch (DecoderFallbackException dfe)//then text is not entirely valid UTF8, contains Codepage 1252 characters that can't be correctly decoded to UTF8
{
var codepage1252Encoding = Encoding.GetEncoding(WindowsCodepage1252, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
text = File.ReadAllText(file, codepage1252Encoding);
}
return text;
}
還值得注意的是StreamReader類具有采用特定 Encoding 對象的構造函數,正如我所展示的,您可以調整 EncoderFallback/DecoderFallback 行為以滿足您的需要。 因此,如果您需要 StreamReader 或StreamWriter來進行更細粒度的工作,仍然可以使用這種方法。
我用它來將文件編碼轉換為 UTF-8
public static void ConvertFileEncoding(String sourcePath, String destPath)
{
// If the destination's parent doesn't exist, create it.
String parent = Path.GetDirectoryName(Path.GetFullPath(destPath));
if (!Directory.Exists(parent))
{
Directory.CreateDirectory(parent);
}
// Convert the file.
String tempName = null;
try
{
tempName = Path.GetTempFileName();
using (StreamReader sr = new StreamReader(sourcePath))
{
using (StreamWriter sw = new StreamWriter(tempName, false, Encoding.UTF8))
{
int charsRead;
char[] buffer = new char[128 * 1024];
while ((charsRead = sr.ReadBlock(buffer, 0, buffer.Length)) > 0)
{
sw.Write(buffer, 0, charsRead);
}
}
}
File.Delete(destPath);
File.Move(tempName, destPath);
}
finally
{
File.Delete(tempName);
}
}
我是如何解決這個問題的:我有 vCard 文件 (*.vcf) - 俄語文件中的 200 個聯系人......我用 vCardOrganizer 2.1 程序打開它,然后使用 Split 將它划分為 200 ......我看到的是 -接觸雜亂的符號,只有我能讀懂它的數字:-) ...
步驟:(執行此步驟時請耐心等待,有時需要時間)用“記事本”打開 vCard 文件(我的文件大小為 3mb)然后從菜單 - 文件-另存為..在打開的窗口中選擇文件名,不要忘記把 .vcf 和編碼 - ANSI 或 UTF-8...最后點擊保存...我將 filename.vcf (UTF-8) 轉換為 filename.vcf (ANSI) - 沒有丟失和完美可讀的俄語語言...如果你有任務寫:yoshidakatana@gmail.com
祝你好運 !!!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.