Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用默认编码从文件中读取字符串后,如何更改字符串编码?_C#_.net_Encoding - Fatal编程技术网

C# 使用默认编码从文件中读取字符串后,如何更改字符串编码?

C# 使用默认编码从文件中读取字符串后,如何更改字符串编码?,c#,.net,encoding,C#,.net,Encoding,我想读取文本文件,该文件的内容中包含有关编码的信息。在我读取文件之前,我不知道使用了什么编码。我使用System.IO.File.ReadAllText读取文件。如何在不再次读取文件的情况下转换编码 我试图在读取文件并将其转换为最终编码时指定默认编码,但转换不正确: string input = File.ReadAllText(filePath, Encoding.Default); Encoding encoding = GetEncodingFromInput(input); input

我想读取文本文件,该文件的内容中包含有关编码的信息。在我读取文件之前,我不知道使用了什么编码。我使用System.IO.File.ReadAllText读取文件。如何在不再次读取文件的情况下转换编码

我试图在读取文件并将其转换为最终编码时指定默认编码,但转换不正确:

string input = File.ReadAllText(filePath, Encoding.Default);
Encoding encoding = GetEncodingFromInput(input);
input = encoding.GetString(Encoding.Convert(Encoding.Default, encoding, Encoding.Default.GetBytes(input)));
转换后的字符串不包含与使用正确编码读取时相同的字符。某些字符更改为问号。

使用System.IO.File.ReadAllBytes读取文件,然后在知道需要哪种编码后,使用类似于:System.Text.encoding.XXXX.GetString的方法对字节数组进行反编码

在我读取文件之前,我不知道使用了什么编码

通常,以某种方式自我声明其编码的文件都有一个文档化的技术或方法来查找它-检查文件格式的已发布文档

如果没有,以下是一些常见的技巧:

在前几个字节中查找Unicode BOM表。您可以先将文件中的前5个字节读入缓冲区或64位整数,然后在字典中查找。这是System.IO.StreamReader默认执行的操作。 您可以在此处看到已知BOM表字节序列的列表: 请注意,UTF-8没有BOM表,但许多编辑器都会在开始时粘贴0xEF 0xBB 0xBF。 如果它是一个text/*-文件格式家族,并且在某种头中声明了编码,那么您可以将文件的第一个千字节读入缓冲区,并将0x7F下的每个连续字节解释为ASCII字符串中的字符,然后使用简单的解析器even string.IndexOf或Regex查找头的分隔符。 这种技术通常用于HTML文件,其中HTTP头声明编码不可用,程序需要查找以获取编码名称。 我使用System.IO.File.ReadAllText读取文件。如何在不再次读取文件的情况下转换编码


你没有。对于编码一致且已知的简单文本/普通文件,只能使用ReadAllText,否则需要同时使用Stream和StreamReader,可能还需要使用BinaryReader。

从各种注释中可以看出,文本位于IBM扩展的8位ASCII代码页(也称为437)中。要加载该代码页中的文件,请使用Encoding.GetEncoding437,例如:

那个?或� 字符是尝试使用错误的代码页读取文本时返回的转换错误替换字符。无法从中恢复原始文本

是系统的默认代码页,而不是.NET范围内的默认代码页。正如文件所说:

.NET Framework中的默认属性 在Windows桌面上的.NET Framework中,默认属性始终获取系统的活动代码页,并创建与其对应的编码对象。活动代码页可以是ANSI代码页,其中包括ASCII字符集以及因代码页而异的其他字符。因为基于ANSI代码页的所有默认编码都丢失数据,因此考虑使用EncOut.UTF8编码。UTF-8通常在U+00到U+7F范围内是相同的,但可以对ASCII范围以外的字符进行编码而不会丢失

最后,两者及其使用的类都将尝试从文件的BOM字节顺序标记中检测编码,如果找不到BOM,则返回UTF8

检测代码页

没有可靠的方法检测编码,因为许多代码页可能使用相同的字节。人们只能可靠地识别错误匹配,因为结果文本将包含�

我们可以做的是加载文件的字节一次,然后尝试多种编码,消除那些包含�. 另一个步骤是检查预期的非英语单词或字符,并消除不产生它们的编码

将返回所有已注册的编码。查找可能编码的粗略方法可以是:

IEnumerable<Encoding> DetectEncodings(byte[] buffer)
{
    var candidates=from enc in Encoding.GetEncodings()
                   let text=enc.GetString(byte)
                   where !text.Contains('�')
                   select enc;
   return candidates;
}
或者,使用值元组:

IEnumerable<(Encoding,string)> DetectEncodings(byte[] buffer)
{
    var candidates=from enc in Encoding.GetEncodings()
                   let text=enc.GetString(byte)
                   where !text.Contains('�')
                   select (enc,text);
   return candidates;
}

不要。您无法恢复由于编码错误而丢失的文本。从一开始就使用正确的编码,或者不指定编码。ReadAllText将尝试检测文件是否为UTF8/UTF16,如果无法检测,则返回默认设置,即系统的区域设置t@Governor注意:编码。默认值并不像你想象的那样。。。Encoding.Default实际上是为当前代码页指定ANSI编码,这是一种传统编码。@MatthewWatson Not true文章说明了该编码。Default是此.NET实现的默认编码,但也说明不同的计算机可以使用不同的编码作为默认编码,默认编码可以在一台计算机上更改。我建议您将文件读取为encoding.Unicode。首先,它是该索赔的C标准,其次是向后补偿
与ASCII和ANSI兼容。因此,即使文件编码为ASCII或ANSI,您仍然可以使用Unicode@MindSwipe我假设这是.Net框架而不是.Net核心,在这种情况下,它将是ANSI编码。Net Core将始终使用UTF8,谢谢,但这正是我试图避免的。@Governor您不能?是错误字符,这意味着原始字符已经消失。@我不知道我是否误解了您的意思,看起来您希望避免实际读取文件两次。您可以使用ReadAllBytes执行一次读取,然后转换一次字节数组,检查需要的编码,然后从仍在内存中的原始字节数组再次转换它。如果您不想将整个内容转换两次,可以通过DaiReadAllText检查另一个答案,尝试从BOM中检测编码并返回默认值。即使使用其他类,您也需要了解advanceIt的SIE格式文件和文档中的编码。该文件和文档表示,目前它只允许IBM扩展的8位ASCII编码,但它可以在将来更改,我希望处理这种可能性。我想我必须使用这个,并且相信它总是正确的。@IBM扩展8位ASCII是437代码页。使用Encoding.GetEncoding437。@PanagiotisKanavos:我知道这一点,这就是我到目前为止一直在做的事情。@在这种情况下,实际的问题应该是如何检测文件的编码,而不是如何转换编码。
IEnumerable<(Encoding,string)> DetectEncodings(byte[] buffer)
{
    var candidates=from enc in Encoding.GetEncodings()
                   let text=enc.GetString(byte)
                   where !text.Contains('�')
                   select (enc,text);
   return candidates;
}