我们的项目中会包含有很多文件,但是可能我们没有注意到的,我们的文件的编码不一定是utf-8,所以可能在别人电脑运行时出现乱码。最近在做一个项目,这个项目可以把我们的文件夹里的所有文本,判断他们是什么编码,如果不是用户规定的编码,那么就告诉用户,是否要把它规范为设置的编码。
<!--more-->
我们常用的编码有 UTF-8 和 GBK ,所以这就是我们的重点关注编码,可惜现在没有一个好的办法区别 UTF-8 和 GBK 。
如果是带 BOM 的文件,带 BOM 就是带签名,我们可以看到在 VisualStudio 的 文件-高级保存 有 UTF-8 带签名和 UTF-8 编码。
那么带签名的意思是什么,这个和历史有关,我们做出了太多编码,有时无法解析文件的编码,如我们在记事本写上联通,再次打开会是乱码的原因一样,为了让文件自己告诉是什么编码,我们就取文件的前四个 byte ,用于让文件说出自己的编码。
对带签名文件,我们可以简单得到他的编码。See:http://lindexi.oschina.io/lindexi/post/win10-uwp-%E8%AF%BB%E5%8F%96%E6%96%87%E6%9C%ACGBK%E9%94%99%E8%AF%AF/
private static Encoding AutoEncoding(byte[] bom)
{
if (bom.Length != 4)
{
throw new ArgumentException("EncodingScrutator.AutoEncoding 参数大小不等于4");
}
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)
return Encoding.Unicode;
if (bom[0] == 0xfe && bom[1] == 0xff)
return Encoding.BigEndianUnicode;
if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32;
return Encoding.ASCII;
}
那么对于没有带签名的文件,我们如何判断?其实我找了现在很多大神的博客,他们都认为这个是没有一个可行的方法,精确判断。所以我们只能通过一个近似的方法来判断。
找了很久,发现了一个很好的算法,对于文件长度不是3的倍数,和包含有中文、ASCII字符的 GBK 编码文件,几乎不会与UTF8混淆。
我们统计属于 GBK 的 byte 个数和属于UTF8的byte个数,比较两个个数,如果countGBK 大于 countUtf8 那么编码就是 GBK,否则是 UTF8。如果相同,gg,所以我们需要一个置信度变量。
看起来我们需要好多变量,于是写一个类
using System.IO;
using System.Text;
namespace EncodingNormalior.Model
{
public class EncodingScrutatorFile
{
public FileInfo File { set; get; }
public Encoding Encoding { set; get; }
public double ConfidenceCount { set; get; } = 0;
}
}
那么如何统计文件中属于 GBK的 byte 个数
我们需要知道 GBK 的编码,对于一般的 ASCII 字符,使用一个 byte 和ASCII一样,如果一个文件都是 ASCII 字符,那么GBK 编码和 ASCII 的都一样,我们统计得到属于 GBK的byte个数为0。对于其他的字符,使用两个 byte 表示。
我找到了一个大神写的判断,https://gist.github.com/neesenk/956765
实际上试过了,不如使用firstByte >= 161 && firstByte <= 247 && secondByte >= 161 && secondByte <= 254
判断。
那么知道了如何判断一个字符是属于GBK,那么我们可以开始写函数CountGbk
private int CountGbk()
{
var count = 0;
if (CountBuffer == null)
{
ReadStream();
}
var length = CountBuffer.Length;
var buffer = CountBuffer;
const char head = (char) 0x80;
for (var i = 0; i < length; i++)
{
var firstByte = buffer[i];
if ((firstByte & head) == 0)
{
continue;
}
if (i + 1 >= length)
{
break;
}
var secondByte = buffer[i + 1];
if (firstByte >= 161 && firstByte <= 247 &&
secondByte >= 161 && secondByte <= 254)
{
count += 2;
i++;
}
}
return count;
}
统计文件中属于 utf8 的byte个数
private int CountUtf8()
{
var count = 0;
if (CountBuffer == null)
{
ReadStream();
}
var length = CountBuffer.Length;
var buffer = CountBuffer;
const char head = (char) 0x80;
{
for (var i = 0; i < length; i++)
{
var temp = buffer[i];
if (temp < 128)
{
continue;
}
var tempHead = head;
var wordLength = 0;
while ((temp & tempHead) != 0)
{
wordLength++;
tempHead >>= 1;
}
if (wordLength <= 1)
{
continue;
}
wordLength--;
if (wordLength + i >= length)
{
break;
}
var point = 1;
for (; point <= wordLength; point++)
{
var secondChar = buffer[i + point];
if ((secondChar & head) == 0)
{
break;
}
}
if (point > wordLength)
{
count += wordLength + 1;
i += wordLength;
}
}
}
return count;
}
我们判断如果是不带签名的文件,判断为 UTF8 或GBK,可以使用判断属于 GBK 的 byte 多还是 UTF8 多。
var countUtf8 = CountUtf8();
if (countUtf8 == 0)
{
encoding = Encoding.ASCII;
}
else
{
var countGbk = CountGbk();
if (countUtf8 > countGbk)
{
encoding = Encoding.UTF8;
EncodingScrutatorFile.ConfidenceCount = (double) countUtf8/(countUtf8 + countGbk);
}
else
{
encoding = Encoding.GetEncoding("GBK");
EncodingScrutatorFile.ConfidenceCount = (double) countGbk/(countUtf8 + countGbk);
}
}
下面是我看到的大神的博客,如果希望了解编码的问题,可以参见下面的博客。
我把项目开源,希望能帮到大家。
https://github.com/lindexi/EncodingNormalior
听说项目的名字拼错了,大家不要笑。
参见:http://blog.csdn.net/wwlhsgs/article/details/45641997
http://blog.csdn.net/wgw335363240/article/details/41700045
http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
http://blog.codingnow.com/2010/06/detect_utf-8_gbk.html
https://msdn.microsoft.com/en-us/library/dd374101(VS.85).aspx
文章还发在 https://lindexi.github.io/lindexi/post/C-%E5%88%A4%E6%96%AD%E6%96%87%E4%BB%B6%E7%BC%96%E7%A0%81/ 他会更新比较快,如果遇到任何的问题,欢迎交流
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。
<script type="text/javascript">
$(function () {
$('pre.prettyprint code').each(function () {
var lines = $(this).text().split('\n').length;
var $numbering = $('<ul/>').addClass('pre-numbering').hide();
$(this).addClass('has-numbering').parent().append($numbering);
for (i = 1; i <= lines; i++) {
$numbering.append($('<li/>').text(i));
};
$numbering.fadeIn(1700);
});
});
</script>
分享到:
相关推荐
以下是获取文件编码的一个类: using System; using System.IO; using System.Text; /// /// FileEncoding 的摘要说明 /// namespace FileEncoding { /// /// 获取文件的编码格式 /// public class Encoding...
本文实例讲述了C#简单判断字符编码的方法。分享给大家供大家参考,具体如下: public static string GetText(byte[] buff) { string strReslut = string.Empty; if (buff.Length > 3) { if (buff[0] == 239 && ...
为了自动识别文件的编码格式,我们需要编写一个程序,它能够读取文件的前几个字节(通常为2或4个字节),然后根据这些字节的值来判断可能的编码。这个过程称为"字节顺序标记"(BOM)检测,或者对于无BOM的编码,通过...
"C#检测文本文件编码的方法" C#检测文本文件编码的方法是指使用C#语言来检测文本文件的编码方式。文本文件的编码方式有多种,如UTF-8、Windows-1252、ASCII等,每种编码方式都有其特点和应用场景。检测文本文件的...
C#中识别文件的编码是一个头疼的问题,最近在做导入微信商户后台退款数据时,无论怎么设置编码导出来都是乱码,后来在网上找了这个识别文件编码的代码,感觉不错。最后识别出来是gb2312,看来我还是太渣了,只能吃土...
通过检查文件的字节模式,可以大致判断其编码类型。 开发自己的编码检测工具时,可以结合字节模式、BOM(如果存在)以及已知字符集的特征进行分析。例如,UTF8有特定的BOM(0xEF, 0xBB, 0xBF),而GBK没有BOM。 总...
"C# text文件编码批量转换"是一个关键的主题,它涉及到对文件读取、编码识别以及转换的核心技术。在此,我们将深入探讨如何在C#中实现这些功能。 首先,我们需要理解各种编码的基本概念。ANSI编码,通常指的是基于...
本文实例总结了C#判断字符编码的方法。分享给大家供大家参考,具体如下: 方法一 在unicode 字符串中,中文的范围是在4E00..9FFF:CJK Unified Ideographs。 通过对字符的unicode编码进行判断来确定字符是否为中文。 ...
C# 文件字符编码识别,识别 ASCII、UTF8、UTF16、UTF32 编码,包含是否 BOM 标记,不管文件头是否存在 BOM 标记,都能准确识别。
总的来说,通过NChardet库和相关的C#源码,我们可以有效地在程序中实现文本文件编码的自动识别,提高程序的兼容性和适应性。正确地处理文本编码,是保障软件正常运行和用户体验的关键步骤之一。
C#方式实现 一个检测文件编码的 代码片段,可检测出UTF8,Unicode,GBK 等编码格式。
"获取zip文件编码格式 cpdetector.zip" 是一个工具,它能够帮助我们识别ZIP文件内文本文件的编码格式。 这个工具的关键依赖于三个JAR文件:antlr-1.0.jar、cpdetector-1.08.jar和jchardet-1.0.jar。这些库提供了...
然后,针对每个文件,通过判断其文件类型(如检查扩展名),决定是否进行编码转换。这通常可以通过`Path.GetExtension`方法来获取文件扩展名。 此外,文件类型过滤功能可能是通过正则表达式或者简单的字符串比较...
- 当保存的文件编码与网页指定的编码不一致时,会导致解码问题,出现乱码。 3. **字符存储**: - 计算机内部只存储字符的编号(编码值),根据字符集的对应关系,读取时查找对应的字符并显示。 - ASCII码的前128...
4. **处理结果**:根据`filesAreSame`的值来判断文件内容是否相同,然后关闭文件流。 ```csharp if (filesAreSame) { Console.WriteLine("两个文件内容相同"); } else { Console.WriteLine("两个文件内容不同"); }...
在MP3文件中,压缩方式指的是音频数据如何被编码以减少存储空间。MP3使用了基于离散余弦变换(DCT)的有损压缩技术,将音频信号转化为频域表示,然后丢弃人耳难以察觉的部分,达到高效的压缩效果。 "层"信息是指MP3...
本文将深入探讨如何使用C#实现文本文件的读取,并介绍相关的类库和方法,以及如何判断文件是否已被打开。 一、基础概念 在C#中,文本文件读取主要依赖于`System.IO`命名空间中的类,如`StreamReader`和`FileStream`...
FO-DICOM是基于.NET的开源库,它为C#开发者提供了解析和操作DICOM文件的能力。PACS(Picture Archiving and Communication System)则是用于存储、管理和检索医学影像的系统。本教程将详细讲解如何使用C#通过FO-...