【问题标题】:Convert from ANSI to UTF-8 Encoding从 ANSI 转换为 UTF-8 编码
【发布时间】:2018-05-01 21:25:47
【问题描述】:

我有一个用 C# 编写的 ASP.Net 4.0 Web 应用程序,它所做的其中一件事是根据从 SQL Server 2012 查询中提取的数据将文件写入文件系统。有时用户输入包含来自法语的字符,经常从 Microsoft Word 剪切和粘贴,因此采用 ANSI 编码。然后,我的 Web 应用程序创建的这个文件通过我无法控制的代码(即不在我的 Web 应用程序中)加载到另一个程序中。问题是第二个程序需要 UTF-8 编码。我已经编写了将程序的输出转换为 UTF-8 的代码,但它仍然无法正确加载,所以我认为我做错了什么。这是我的代码:

protected void writeToClientFile(DataSet ClientGenl, DataSet ClientBus, DataSet ClientBill)
    {
        FileStream fileStream = null;
        string fileName = "ClientTest.txt";
        string pathName = ConfigurationSettings.AppSettings["EliteFilePath"].ToString();
        try
        {
            using (new KLClassLibrary.Impersonator(proxyaccount, domain, password))
            {
                fileStream = OpenASAP(pathName + fileName, 10);
                using (TextWriter tw = new StreamWriter(fileStream))
                {
                    foreach (DataRow rowGeneral in ClientGenl.Tables[0].Rows)
                    {
                        string fileTextGeneral = "CLNUM:" + rowGeneral["clnum"].ToString().toEliteInput();
                        byte[] originalBytes = Encoding.Default.GetBytes(fileTextGeneral);
                        byte[] convertedBytes = Encoding.Convert(Encoding.Default, Encoding.UTF8, originalBytes);
                        char[] convertedChars = new char[Encoding.UTF8.GetCharCount(convertedBytes, 0, convertedBytes.Length)];
                        Encoding.UTF8.GetChars(convertedBytes, 0, convertedBytes.Length, convertedChars, 0);
                        string convertedString = new string(convertedChars);
                        tw.WriteLine(convertedString);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (fileStream != null)
                fileStream.Dispose();
        }
    }
FileStream OpenASAP(string path, int maxTries)
    {
        FileStream fs = null;
        bool lastResult = false;
        int count = 0;
        while ((lastResult == false) && count < maxTries)
        {
            lastResult = TryOpen(path, out fs);
            Thread.Sleep(100);
            count++;
        }
        if (!lastResult || count >= maxTries)
        {
            throw new Exception("The file is being written to");
        }
        return fs;
    }
bool TryOpen(string FileWithPath, out FileStream fs)
    {
        try
        {
            fs = File.Open(FileWithPath, FileMode.Append, FileAccess.Write, FileShare.None);
            return true;
        }
        catch (Exception ex)
        {
            fs = null;
            return false;
        }
    }

【问题讨论】:

  • rowGeneral["clnum"].ToString().toEliteInput()实际上给出什么样的输出?不知道这一点,就没有办法解决这个问题。
  • 另请注意... all 现代 Windows 版本上的 Windows 剪贴板提供 UTF-8 文本,如果您使用 C# 来获取它,这甚至是无关紧要的,因为您只是自动将其作为String 对象获取。而且,不要使用Encoding.Default,它不会像您认为的那样做。这并不意味着“ansi”。它的意思是“使用这台 PC 上碰巧配置的任何语言的本地编码”,如果你曾经在发生 not 的事情上运行它,这可能会非常错误设置为美式英语。
  • toEliteInput 是一个返回字符串的扩展方法。有没有办法准确地确定它的编码是什么?谢谢。
  • 是的,但我正在尝试确定实际的 problem 是什么,这需要查看您的“错误”输出是什么。有几种方式可以破坏编码文本,修复它的方法取决于您实际得到的内容。你从来没有表现出来。我只是想要一个你从那个查询中得到的东西的例子。无论如何,this answer 在检测编码方面应该会帮助您。
  • 我只是想在这里发帖,我们偶然发现第 3 方供应商告诉我们的内容是错误的。应用程序不接受 UTF-8 编码。它只需要普通的 ANSI,不需要扩展字符。所以真的没有办法让这些角色进入应用程序。这一切都是徒劳的。很抱歉浪费了您的时间,但感谢您的帮助。

标签: c# asp.net encoding utf-8 ansi


【解决方案1】:

您可以从StreamReader.CurrentEncoding 导出原始编码,然后使用Encoding.Convert() 转换编码,将导出的编码指定为源编码,将Encoding.UTF8 指定为目标编码。

这样,您让StreamReader 决定哪种编码适合源文件的内容。
它可能是从默认编码转换而来的 Unicode(Windows 中的 UTF16)。

string TextDestinaton = string.Empty;

using (FileStream FileOrigin = new FileStream(@"[SomeSourceFile]", 
                                   FileMode.Open, FileAccess.Read, FileShare.None))
using (StreamReader orgReader = new StreamReader(FileOrigin))
{
    Encoding OriginalEncoding = Encoding.GetEncoding(orgReader.CurrentEncoding.CodePage);
    byte[] OriginalBytes = OriginalEncoding.GetBytes(orgReader.ReadToEnd());
    byte[] DestinationBytes = Encoding.Convert(OriginalEncoding, Encoding.UTF8, OriginalBytes, 0, OriginalBytes.Length);

    using (MemoryStream memstream = new MemoryStream(DestinationBytes, 0, DestinationBytes.Length))
    using (StreamReader destReader = new StreamReader(memstream, Encoding.UTF8))
    {
        memstream.Position = 0;
        TextDestinaton = destReader.ReadToEnd();
    };
}

请注意:如果原始文本包含不符合本地编码的字符(获取文本时),并且没有使用特定编码来保留源代码页映射,则源文本可能会受到损害。

【讨论】:

  • 我试过你的建议,但它仍然没有给我正确的输出。我没有提到的一件事是数据是从 SQL Server 2012 查询中提取的,然后由我的代码进行操作。我认为这不会改变任何事情,但我也会编辑我的原始问题以包含此内容。
  • @Nyerguds 好吧,如果您不知道原始编码(以及是否保留了原始 CodePage 映射),那么一切都是不可靠的。此代码只是测试使用本地 CodePage 将文本(我认为是文本文件)文件映射到 Unicode 的可能性。确实应该在第一次 read() 之后检查 StreamReader.CurrentEncoding,但是如果可以按照描述映射文本,那么无论如何您都会得到积极的结果。如果不能,您将不得不猜测或找出该文本在本地存储时是如何编码的。
  • @Melanie 你知道原始文本是如何存储在 SQL Server 中的吗?使用varcharnvarchar?如果是nvarchar,它应该是UCS2/UTF16,如果它是varchar,它可能是ISO-8859-1(CP 1252)。如果可以,请检查COLLATIONPROPERTY,并查看使用了什么 CodePage 或 LCID。
  • @Jimi 据我所知,StreamReader 的编码检测完全基于字节序标记。如果文本开头没有特定的指示字节,它将不会自动检测 UTF 编码。
  • @Nyerguds 正确。这就是为什么我在这里不尝试检测特定格式,而是执行部分读取以让 StreamReader 识别 [不可能的] BOM。我正在测试是否可以将源文本转换为保留原始代码页映射的 Unicode。如果可以,则文本(获取时)已正确映射或本地兼容。如果不能,则原始文本已被转码为更宽的格式,或者原始格式丢失。因为现在我知道它来自 SQL DB,所以我建议直接用它的标准编码测试结果。
猜你喜欢
  • 2015-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-20
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
  • 2014-07-02
相关资源
最近更新 更多