ADODB.Stream

读写文本文件时出现了乱码,找到了ADODB.Stream,可以指定字符集读取文本

Function ReadUTF()

    Filename = "F:\vba\2018 - new\2018-10-29 cad打桩\3 - cad打桩\代码\1.txt"

    With CreateObject("ADODB.Stream")
        .Type = 2    '读取文本文件
        .Mode = 3   '读写
        .Open
        .LoadFromFile Filename
'        .Charset = "UTF-8"
'       .Charset = "Unicode"
       .Charset = "GB2312"  'GB2312 = ANSI
        .Position = 2
        ReadUTF = .ReadText
        .Close
    End With
    
    Debug.Print ReadUTF

End Function

发现ANSI竟然就是GB2312,不过百度一下才发现不仅仅是简单的等于GB2312,有个网址讲的非常的到位

http://club.excelhome.net/thread-998747-1-1.html
三、ANSI编码(ISO8859、GB2312、Big5、JIS等等)

      在二楼的介绍中,我们讲解了计算机是如何显示键盘字符的(通常我们称为ASCII字符)。那么,我们伟大的中华民族的汉字多达十万个,常用的也有两三万,这又该如何显示呢?ASCII标准编码只有0~127,
扩展编码128~255,完全放不下这么多汉字嘛。 莫非,电脑发明的时候,就是给英语国家用的? 是的,你猜对了,最早电脑发明的时候,完全没有考虑这个世界上还会有其他的民族也会用到电脑,而这些民族的字符集会多达数万!有人问了,为什么当年的
科学家不考虑地球的其他民族呢?俺猜想,这与当年存储器的容纳能力有关,如果采用一个字节存储英文字符,完全足够了。如果考虑其他民族,就要用两个甚至更多的存储空间来存放英文字符(以便兼容多民族字符),
而为了这种兼容需要多支付的存储空间,其代价是当年的技术所不能承受的。 后来,随着技术的进步,单位存储空间的费用已经降低到了一个可以接受的地步,为地球多民族的字符集做编码,终于变为了可能。ANSI(美国国家标准学会)在这样的背景下,出台了一系列字符集,这些字符
集再加上其他国家为本国语言所设计的早期字符集,统称为ANSI编码。 所以,提到ANSI字符集,你一定要知道,这是一个由许多不同国家的字符集所构成的一个字符集集合的统称,而不是一个特定的字符集。同一个操作系统在不同的国家的ANSI编码,就是这个国家的字符集编码。
例如,欧洲国家用ISO8859(包括15个不同国家的子集)、中国大陆用GB2312、台湾用Big5、日本用JIS等等 ANSI的子集,在不同的操作系统下是不一样的,这取决于操作系统所支持的字符集。例如,同样是简体中文,Win32下的ANSI是GB2312,Windows95是GBK。Windows7是GB18030(完整支持需要安装扩展字体)等 补充内容 (2013-4-27 00:08): GB2312、GBK、 GB18030等都属于双字节字符集 (DBCS double-byte character set)。 DBCS是亚洲字符集,包括简中、繁中、日、韩。在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节
作为一个双字节编码。

后又发现 position如果设置为0,竟然会有一个乱码出现,但是文件的内容为什么不是从0开始的,而是从2开始的(position即光标的位置,就是设置从第几个字符开始读取文件内容),原来前两个字节用来定义文件的编码方式了,不过也不能简单的说是前两个字节,有些编码方式不是前两个字节

Function checkcode(path)

    Set objstream = CreateObject("adodb.stream")
    objstream.Type = 1
    objstream.Mode = 3
    objstream.Open
    objstream.Position = 0
    objstream.LoadFromFile path
    bintou = objstream.read(2)
    
    If bintou(0) = &HEF And bintou(1) = &HBB Then
        checkcode = "utf-8"
        
    ElseIf bintou(0) = &HFF And bintou(1) = &HFE Then
        checkcode = "unicode"
        
    ElseIf bintou(0) = 49 And bintou(1) = 50 Then
        checkcode = "gb2312"
        
    Else
        checkcode = "其他"
    End If
    
'    If AscB(MidB(bintou, 1, 1)) = &HEF And AscB(MidB(bintou, 2, 1)) = &HBB Then
'        checkcode = "utf-8"
'    ElseIf AscB(MidB(bintou, 1, 1)) = &HFF And AscB(MidB(bintou, 2, 1)) = &HFE Then
'        checkcode = "unicode"
'    Else
'        checkcode = "gb2312"
'    End If
    
    objstream.Close
    Set objstream = Nothing
    
End Function

 

AscB(MidB(bintou, 1, 1)) = &HEF

bintou(0) = &HEF

经过测试,两种方式都是可以的,但是个人更喜欢简洁明了一点的方式

 

UTF8文件有BOM和No BOM两种,其区别在于BOM多了三个字节(EFBBBF),对比了二进制文件,发现有这个区别,如果是NoBOM的文件就无法通过前两个字节判断是否为UTF-8文件。

对于没有BOM的UTF-8文件,可以通过遍历判断是否为UTF-8编码。遍历方法可以是二进制的移位判断或者是正则。

https://www.w3.org/International/questions/qa-forms-utf-8

例如,当使用Perl时,可用以下的表达式测试页面是否使用了UTF-8编码:

$field =~
  m/\A(
     [\x09\x0A\x0D\x20-\x7E]            # ASCII
   | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
   |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
   | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
   |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
   |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
   | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
   |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
  )*\z/x;

以上表达式可转换成其他编程语言。这样就能处理各类问题,例如过长的错误编码以及非法的代理使用。$field 属于UTF-8编码时就会顺利返回,否则失败。

 

关于 BOM 和 NO BOM

http://club.excelhome.net/thread-998747-2-1.html

十、网络文本的传输标准(UTF-8)

很多时候,我们不能直接传输Unicode编码的文本字符。因为Unicode编码不是为传输而设计,其编码为硬性规定。对接收方来说,接到了Unicode编码的数据,很难判断这是什么编码格式,会造成识别上的混乱。
为了兼容ASCII字符,并避免遇到\0造成字符串中断,以及解决英文传输体积被填零放大一倍的问题,提出了UTF
-8编码规范。UTF-8的每一个字符按规则编码为1~4任一字节组合。中文大部分为为3字节长,部分四字节。 为了避免在文本传输中发生混乱,互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。 此外,在 Unix 世界中使用 UCS-2( 或 UCS-4) 会导致非常严重的问题。使用这两种编码方式的字符串,可能会包含诸如 字节 "/0""/" 作 为很多宽字符的组成部 分,
而这样的字节在文件名和其它 C 语言库函数中有特殊的意义。此外,大多数 Unix 工具都被设计用来处理 ASCII 文件的,不进行大 幅 度的修改是无法读取 16-bit 字符的。
基于这些原因,在文件名、文本文件、环境变量等地方, UCS-2 ( 或 UCS-4 ) 不是一种合适的 Unicode 外部编码。
在 ISO 10646-1:2000 附 录 D 、 RFC3629 以 及 Unicode 4.0 标准的 3.9 节中均有定义的 UTF-8 编码方法则不存在上述问题。所以在类 Unix 风格的操作系统中使用UTF-8来应用 Unicode编码。 UTF-8编码字节含义 对于UTF-8编码中的任意字节B,如果B的第一位为0,则B为ASCII码,并且B独立的表示一个字符; 如果B的第一位为1,第二位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的一个字节,并且不为字符的第一个字节编码; 如果B的前两位为1,第三位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由两个字节表示; 如果B的前三位为1,第四位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由三个字节表示; 如果B的前四位为1,第五位为0,则B为一个非ASCII字符(该字符由多个字节表示)中的第一个字节,并且该字符由四个字节表示; 因此,对UTF-8编码中的任意字节, 根据第一位,可判断是否为ASCII字符; 根据前二位,可判断该字节是否为一个字符编码的第一个字节;
根据前四位(如果前两位均为1),可确定该字节为字符编码的第一个字节,并且可判断对应的字符由几个字节表示;根据前五位(如果前四位为1),可判断编码是否有错误或数据传输过程中是否有错误。 UTF
-8的设计有以下的多字符组串行的特质: 单字节字符的最高有效比特永远为0。 多字节串行中的首个字符组的几个最高有效比特决定了串行的长度。最高有效位为110的是2字节串行,而1110的是三字节串行,如此类推。 多字节串行中其余的字节中的首两个最高有效比特为10。 UTF-8的这些特质,保证了一个字符的字节串行不会包含在另一个字符的字节串行中。这确保了数据接收方可以从任意一个位置来判断字符的起始字节,适用于在文字中搜索字或词。 另一方面,由于其字节串行设计,如果一个疑似为字符串的串行被验证为UTF-8编码,那么我们可以有把握地说它是UTF-8字符串。一段两字节随机串行碰巧为合法的UTF-8而非ASCII的机率为32分1。
对于三字节串行的机率为256分1,对更长的串行的机率就更低了。这样从概率上能避免识别的错误。 UCS和 Unicode标准中对UTF
-8的定义稍有不同,因为在UCS中,UTF-8字节序列的最大可能长度为6,以表示所有码值不大于U+7FFFFFFF的 字符;而在Unicode中,UTF-8字节序列的最大可能长度为4,
以表示所有码值不大于U+0010FFFF的字符。(这一差别在本质上与UCS-4 和UTF-32之间的相同)。 如何识别文本传输的编码: 最标准的途径是检测文本最开头的几个字节(BOM), 开头字节 Charset/encoding, EF BB BF UTF-8 FF FE UTF-16/UCS-2, little endian -- Windows标准(低位在前),Unicode编码 FE FF UTF-16/UCS-2, big endian FF FE 00 00 UTF-32/UCS-4, little endian. 00 00 FE FF UTF-32/UCS-4, big-endian. 如果传输的文本没有Bom,那就需要采用正则或者其他方式来遍历文本,判断编码规范了。 这里有个有趣的现象。如果你打开记事本,输入联通两个字,然后把文件保存成ANSI格式。当你再次打开的时候,会发现文本乱码。 这是因为"联通"的ANSI/GB2312编码是: c1 1100 0001 aa 1010 1010 cd 1100 1101 a8 1010 1000 恰好符合UTF-8的编码规范,因此造成识别错误。如果你在"联通"之后多输入几个字,其他的字的编码不见得又恰好是110和10开始的字节,这样再次打开时,记事本就不会坚持这是一个utf8编码的文件,
而会用ANSI的方式解读之,这时乱码就不出现了。 对于添加UTF
-8 BOM( 字节串 :0XFF 0XBB 0XBF) 的做法,不被Unicode组织推荐,特别是是不能在 POSIX 系统中采用这种做法。此外,在文件头部添加 UTF-8 签名会对很多已有惯例产生妨碍,例如处理一个纯文本程序。 正则表达式判断数据是否为UTF-8编码, 参考 http://www.w3.org/International/questions/qa-forms-utf-8,后面有参考代码 最后,总结一下各种文本编码: ANSI/GB2312/GBK/GB18030 这些都是区域性编码,没有BOM UNICODE 目前Windows操作系统使用的内码(低位在前),得到大部分编程语言的支持。标准数据有BOM头。 UTF-8/UTF-16 通常我们把这个看作传输编码(Unicode的实现方式),用于互联网数据传输。标准数据可能有BOM头。

最后提供一个详细说明 adodb.stream 对象的属性和方法的网址 

https://blog.csdn.net/icanlove/article/details/39394701

 

posted @ 2019-02-13 17:47  1156740846  阅读(2437)  评论(0编辑  收藏  举报