[英]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.