热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

js版本的文本文件文件保存编码自动检测功能实现与检测原理

关于文件在选择编码保存之后,让我们在读取时如何知道它是什么编码,可以这么做,让我们明白需要根据什么来判断.使用记事本选择不同的编码保存文件,接着使用u

关于文件在选择编码保存之后,让我们在读取时如何知道它是什么编码,可以这么做,让我们明白需要根据什么来判断.

使用记事本选择不同的编码保存文件,

接着使用uedit32使用二进制方式打开这个文件.

观察打开后内容前面几个byte位(如ff是一个,点8bit)不同,即可发现这些位置原来就是保存着编码标志(正常的说,有某些编辑器不按常规来办话那就没办法);

基于这个规则,我们可以使用读取这些byte位来判断即可知道编码是什么了,就能正常显示内容了.

 

而fso是不能干这事的,只能用adodb.stream,或者xmlhttprequest也行

 

本来我想使用ado的二进制的read(2)得到文件的前面二个编码的标志位来判断文件的编码,却发现js无法获取它的值,直接提示出错.虽然可以这部分使用vbs,但是不太想用,今天经过测试与查找资料,终于明白编码一些事情.

失败尝试结果:

var bin2 = ado.read(2);

在ie9调试中得到的值是和出错信息是

js版本的文本文件文件保存编码自动检测功能实现与检测原理 - qidizi - qidizi 的博客

js版本的文本文件文件保存编码自动检测功能实现与检测原理 - qidizi - qidizi 的博客

连alert都不允许,更不用说用bin2 & 0xfffe=0xfffe比较了.

经过测试得知:

 

 js版本的文本文件文件保存编码自动检测功能实现与检测原理 - qidizi - qidizi 的博客

 

像上图,文本编辑器实际只输入一个感叹号!(unicode唯一对应号是u+2100),选择unicode保存(bom是有标志意思, 在win的记事本中是没有bom一名),

在ue中使用二进制查看,发现实际的硬盘空间中前面二byte放了unicode的标志(ff fe)

那么设置ado.type=2//text数据,1是bin数据时

然后ado也会像记事本一样遵守"标志"规则,前面二byte是标志,并不是内容,判断符合,读取后面的二个byte(既是21 00)输出,即position=0;ado.readText(1) == !,

所以你设置成charset是unicode话,它会按"规则"读取,你永远得不到前面二个.byte.

怎么办?

而ibm的codepage 437编码却是这样解析:它刚好是一个字占8bit,且没有编码标志位的规定(这很重要,关键到你是否能得到全部的内容),所以read(1)和position = 0;是从硬盘储存结构意义上的第一位开始读取的,这跟二进制读取是一样的(即position=0, readText(1) == ff, 而不是unicode规则所得到的 21 00).完全跟unicode处理方式不同,且很好一点就是它一个字刚好就是一byte,

接着把字进行转unicode(js的charcodeat方法返回就是了)码再做比较

,437不是国际通用代码,它会在不同地方每个字对应关系不一样,

有可能在美国,硬盘中一byte位00对应美国字a,而在中国, 00对应的字是 我

,那么你用var c = ado.read(1) 与 我 比较,在中国电脑是对应的,因为byte的00 与我的 unicode是相同的;

,而在美国却跟a不是相同的,a的unicode并不是00

,因为字符比较在js中是需要转成unicode对应编码来比较的,a与我在unicode并不相同,所以结果就不同了.

unicode的编码却是在全球是固定意义的.且ado.read返回的就是unicode码,显示时再转成对应的本地系统的对应字来的,

而它在硬盘中的二进制保存值跟unicode有绝对的对应关系,通过这关系,就能得到直正的硬盘中保存的二进制值了.这是这代码的关键

 

然后我们得知每种编码使用多少个位置byte做标志,且值是什么,我们进行比较就知道本文件是什么编码了(肯定这些编码标志不会冲突的)

至于某些程序能智能分析,有些是根据后缀再查找里面内容的设置,如html文件,它可以查找 content-type charset=什么来确定应该按什么来解析字符,但是如果你保存时并不是charset=指定相同的编码话,在浏览器中查看时肯定也是乱码的.

 

下面是ansi与unicode绝对的对应关系.因为一个byte位刚好就是8bit,只能是0-ff,使用cp437来读取肯定不会一个byte会是个100(ff + 1)

 

表的查找方法是:如要找ef话,就是左边是e0,上边是0f的交点,小框中上面是437对应的字,下面 是对应的unicode码.是16进制的需要使用0x表示

js版本的文本文件文件保存编码自动检测功能实现与检测原理 - qidizi - qidizi 的博客

-------------------js+ado代码----


    var cPath = 'G:/sys/qidizi/desktop/s.css';
    var ado = new ActiveXObject("adodb.stream");
    ado.Type = 2;//指定返回数据类型是text   
    ado.Mode = 3;//指定控件对象是读写模式       
    ado.CharSet = '437';//ibm的cp437编码是0-255[0-ff],刚好是每个字点8bit位,且没有文件头标志位,会让ado从绝对意义上的第一个byte开始读取
    ado.Open();//准备缓存   
    ado.Position = 0;//初始化指针
    ado.LoadFromFile(cPath);//把文件读入缓存
    var byte1 = ado.ReadText(1).charCodeAt(0);//读入第一个字|第一个byte
    var byte2 = ado.ReadText(1).charCodeAt(0);//读入二个字节|第二个byte位值
    var byte3 = ado.ReadText(1).charCodeAt(0);//读入三个字节
    var byte4 = ado.ReadText(1).charCodeAt(0);//读入四个字节

    if (byte1 == 0x00A0 && byte2 == 0x25a0) {//unicode标志码是二个 ff = u+00A0  fe = U+25A0
        var charset = 'unicodeFFFe';//在注册表中是这个名字
    } else {//没有标志位,那么按默认来处理吧,中国人使用gbk
        var charset = 'gbk';//中文系统的ansii
    }
    
    ado.Position = 0;//重设读取指针,让ado重新开始
    ado.CharSet = charset;//指定真正的文件保存字符编码集,请看注册表中:HKEY_CLASSES_ROOT\MIME\Database\Charset\
    var css = ado.ReadText();//把整个文件内容按保存编码正确读取出来
    ado.Close();
    ado = null;
    alert(css);

------------运行结果

js版本的文本文件文件保存编码自动检测功能实现与检测原理 - qidizi - qidizi 的博客

 

如果使用ansi与无标志utf8,是无法从标志区别,估计一般做法是先使用utf8来判断,如果出现了无法输入的可打印字符,就应该是ansi.


推荐阅读
  • 图像因存在错误而无法显示 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • Activiti7流程定义开发笔记
    本文介绍了Activiti7流程定义的开发笔记,包括流程定义的概念、使用activiti-explorer和activiti-eclipse-designer进行建模的方式,以及生成流程图的方法。还介绍了流程定义部署的概念和步骤,包括将bpmn和png文件添加部署到activiti数据库中的方法,以及使用ZIP包进行部署的方式。同时还提到了activiti.cfg.xml文件的作用。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • 本文介绍了在实现了System.Collections.Generic.IDictionary接口的泛型字典类中如何使用foreach循环来枚举字典中的键值对。同时还讨论了非泛型字典类和泛型字典类在foreach循环中使用的不同类型,以及使用KeyValuePair类型在foreach循环中枚举泛型字典类的优势。阅读本文可以帮助您更好地理解泛型字典类的使用和性能优化。 ... [详细]
author-avatar
乌龙小和尚
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有