阅读更多

2顶
0踩

编程语言

原创新闻 字符编码的前世今生

2017-11-01 09:39 by 副主编 jihong10102006 评论(0) 有15374人浏览
引用
作者:刘志军

前言

很多程序员对字符编码不太理解,虽然他们大概知道 ASCII、UTF8、GBK、Unicode 等术语概念,但在写代码过程中还是会遇到各种奇怪的编码问题,在 Java 中最常见的是乱码,而 Python 开发中遇到最多的是编码错误,如:UnicodeDecodeError、UnicodeEncodeError,几乎每个 Python 开发者都会碰到这种问题,对此都是一筹莫展,这篇文章从字符编码的起源开始,讲述了编程中应该如何应对编码的问题,通过理解本文,你可以从容地定位、分析、解决字符编码相关的问题。

说到「字符编码」我们先要理解什么是编码以及为什么要编码。

什么是编码

但凡学过计算机的同学都知道,计算机只能处理0和1组成的二进制数据,人类借助计算机所看到的、听到的任何信息,包括:文本、视频、音频、图片在计算机中都是以二进制形式进行存储和运算。计算机善于处理二进制数据,但是人类对于二进制数据显得捉襟见肘,为了降低人与计算机的交流成本,人们决定把每个字符进行编号,比如给字母 A 的编号是 65,对应的二进制数是「01000001」,当把 A 存到计算机中时就用 01000001 来代替,当要加载显示在文件中或网页中用来阅览时,就把二进制数转换成字符 A,这个过程中就会涉及到不同格式数据之间的转换。

编码(encode)是把数据从一种形式转换为另外一种形式的过程,它是一套算法,比如这里的字符 A 转换成 01000001 就是一次编码的过程,解码(decode)就是编码的逆过程。今天我们讨论的是关于字符的编码,是字符和二进制数据之间转换的算法。密码学中的加密解密有时也称为编码与解码,不过它不在本文讨论范围内。

什么是字符集

字符集是一个系统支持的所有抽象字符的集合。它是各种文字和符号的总称,常见的字符集种类包括 ASCII 字符集、GBK 字符集、Unicode字符集等。不同的字符集规定了有限个字符,比如:ASCII 字符集只含有拉丁文字字母,GBK 包含了汉字,而 Unicode 字符集包含了世界上所有的文字符号。

有人不禁要问,字符集与字符编码是什么关系?别急,先往下面

ASCII:字符集与字符编码的起源

世界上第一台计算机,1945年由美国宾夕法尼亚大学的两位教授-莫奇利和埃克特设计和研制出来,美国人起草了计算机的第一份字符集和编码标准,叫 ASCII(American Standard Code for Information Interchange,美国信息交换标准代码),一共规定了 128 个字符及对应的二进制转换关系,128 个字符包括了可显示的26个字母(大小写)、10个数字、标点符号以及特殊的控制符,也就是英语与西欧语言中常见的字符,这128个字符用一个字节来表示绰绰有余,因为一个字节可以表示256个字符,所以当前只利用了字节的7位,最高位用来当作奇偶校验。如下图所以,字符小写 a 对应 01100001,大写 A 对应 01000001。

ASCII 字符集是字母、数字、标点符号以及控制符(回车、换行、退格)等组成的128个字符。ASCII 字符编码是将这128个字符转换为计算机可识别的二进制数据的一套规则(算法)。现在可以回答前面的那个问题了,通常来说,字符集同时定义了一套同名的字符编码规则,例如 ASCII 就定义了字符集以及字符编码,当然这不是绝对的,比如 Unicode 就只定义了字符集,而对应的字符编码是 UTF-8,UTF-16。

ASCII 由美国国家标准学会制定,1967年定案,最初是美国国家标准,后来被国际标准化组织(International Organization for Standardization, ISO)定为国际标准,称为ISO 646标准,适用于所有拉丁文字字母。

EASCII:扩展的ASCII

随着计算机的不断普及,计算机开始被西欧等国家使用,然后西欧语言中还有很多字符不在 ASCII 字符集中,这给他们使用计算机造成了很大的限制,就好比在中国,你只能用英语跟人家交流一样。于是乎,他们想着法子把 ASCII 字符集进行扩充,以为 ASCII 只使用了字节的前 7 位,如果把第八位也利用起来,那么可表示的字符个数就是 256。这就是后来的 EASCII(Extended ASCII,延伸美国标准信息交换码)EASCII 码比 ASCII 码扩充出来的符号包括表格符号、计算符号、希腊字母和特殊的拉丁符号。

然后 EASCII 并没有形成统一的标准,各国个商家都有自己的小算盘,都想在字节的高位做文章,比如 MS-DOS, IBM PC上使用了各自定义的编码字符集,为了结束这种混乱的局面,国际标准化组织(ISO)及国际电工委员会(IEC)联合制定的一系列8位元字符集的标准,叫 ISO 8859,全称ISO/IEC 8859,它在 ASCII 基础之上扩展而来,所以完全 ASCII,ISO 8859 字符编码方案所扩展的这128个编码中,只有0xA0~0xFF(十进制为160~255)被使用,其实 ISO 8859是一组字符集的总称,旗下共包含了15个字符集,分别是 ISO 8859-1 ~ ISO 8859-15,ISO 8859-1 又称之为 Latin-1,它是西欧语言,其它的分别代表 中欧、南欧、北欧等字符集。

GB2312:满足国人需求的字符集

后来,计算机开始普及到了中国,但面临的一个问题就是字符,汉字博大精深,常用汉字有3500个,已经大大超出了 ASCII 字符集所能表示的字符范围了,即使是 EASCII 也显得杯水车薪,1981 年国家标准化管理委员会定了一套字符集叫 GB2312,每个汉字符号由两个字节组成,理论上它可以表示65536个字符,不过它只收录了7445个字符,6763个汉字和682个其他字符,同时它能够兼容 ASCII,ASCII 中定义的字符只占用一个字节的空间。

GB2312 所收录的汉字已经覆盖中国大陆99.75%的使用频率,但是对一些罕见的字和繁体字还有很多少数民族使用的字符都没法处理,于是后来就在 GB2312 的基础上创建了一种叫 GBK 的字符编码,GBK 不仅收录了27484 个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。GBK 是利用了 GB2312 中未被使用的编码空间上进行扩充,所以它能完全兼容 GB2312和 ASCII。而 GB 18030 是现时最新的字符集,兼容 GB 2312-1980 和 GBK, 共收录汉字70244个,采用多字节编码,每个字符可以有1、2、4个字节组成,某种意义上它能容纳161 万个字符,包含繁体汉字以及日韩汉字,单字节与ASCII兼容,双字节与GBK标准兼容。

Unicode :统一江湖的字符集

尽管我们有了属于自己的字符集和字符编码 GBK,可世界上还有很多国家拥有自己的语言和文字,比如日本用 JIS,台湾用 BIG5,不同国家之间交流起来就很困难,因为没有统一的编码标准,可能同一个字符,在A国家用两字字节存储,而到了B国家是3个字节,这样很容易出现编码问题,于是在 1991 年,国际标准化组织和统一码联盟组织各自开发了 ISO/IEC 10646(USC)和 Unicode 项目,这两个项目的目的都是希望用一种字符集来统一全世界所有字符,不过很快双方都意识到世界上并不需要两个不兼容的字符集。于是他们就编码问题进行了非常友好地会晤,决定彼此把工作内容合并,虽然项目还是独立存在,各自发布各自的标准,但前提是两者必须保持兼容。不过由于 Unicode 这一名字比较好记,因而它使用更为广泛,成为了事实上的统一编码标准。

以上是对字符集历史的一个简要回顾,现在重点来说说Unicode,Unicode 是一个囊括了世界上所有字符的字符集,其中每一个字符都对应有唯一的编码值(code point),注意了!它不是字符编码,仅仅是字符集而已,Unicode 字符如何进行编码,可以是 UTF-8、UTF-16、甚至用 GBK 来编码。例如:
>>> a = u"好"
>>> a
u'\u597d'
>>> b = a.encode("utf-8")
>>> b
'\xe5\xa5\xbd'
>>>

>>> b = a.encode("gbk")
>>> b
'\xba\xc3'

Unicode 本身并没有规定一个字符究竟是用一个还是三个或者四个字节表示。Unicode 只规定了每个字符对应到唯一的代码值(code point),代码值 从 0000 ~ 10FFFF 共 1114112 个值 ,真正存储的时候需要多少个字节是由具体的编码格式决定的。比如:字符 「A」用 UTF-8 的格式编码来存储就只占用1个字节,用 UTF-16 就占用2个字节,而用 UTF-32 存储就占用4个字节。

UTF-8:Unicode编码

UTF( Unicode Transformation Format)编码 和 USC(Universal Coded Character Set) 编码分别是 Unicode 、ISO/IEC 10646 编码体系里面两种编码方式,UCS 分为 UCS-2 和 UCS-4,而 UTF 常见的种类有 UTF-8、UTF-16、UTF-32。因为 Unicode 与 USC 两种字符集是相互兼容的,所以这几种编码格式也有着对应的等值关系

UCS-2 使用两个定长的字节来表示一个字符,UTF-16 也是使用两个字节,不过 UTF-16 是变长的(网上很多错误的说法说 UTF-16是定长的),遇到两个字节没法表示时,会用4个字节来表示,因此 UTF-16 可以看作是在 UCS-2 的基础上扩展而来的。而 UTF-32 与 USC-4 是完全等价的,使用4个字节表示,显然,这种方式浪费的空间比较多。

UTF-8 的优势是:它以单字节为单位用 1~4 个字节来表示一个字符,从首字节就可以判断一个字符的UTF-8编码有几个字节。如果首字节以0开头,肯定是单字节编码,如果以110开头,肯定是双字节编码,如果是1110开头,肯定是三字节编码,以此类推。除了单字节外,多字节UTF-8码的后续字节均以10开头。

1~4 字节的 UTF-8 编码看起来是这样的:
引用
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

  • 单字节可编码的 Unicode 范围:\u0000~\u007F(0~127)
  • 双字节可编码的 Unicode 范围:\u0080~\u07FF(128~2047)
  • 三字节可编码的 Unicode 范围:\u0800~\uFFFF(2048~65535)
  • 四字节可编码的 Unicode 范围:\u10000~\u1FFFFF(65536~2097151)
UTF-8 兼容了 ASCII,在数据传输和存储过程中节省了空间,其二是UTF-8 不需要考虑大小端问题。这两点都是 UTF-16 的劣势。不过对于中文字符,用 UTF-8 就要用3个字节,而 UTF-16 只需2个字节。而UTF-16 的优点是在计算字符串长度,执行索引操作时速度会很快。Java 内部使用 UTF-16 编码方案。而 Python3 使用 UTF-8。UTF-8 编码在互联网领域应用更加广泛。

来看一张图,下图是Windows平台保存文件时可选择的字符编码类型,你可以指定系统以什么样的编码格式来存储文件,ANSI 是 ISO 8859-1的超集,之所以在 Windows下有 Unicode 编码这样一种说法,其实是 Windows 的一种错误表示方法,或许是因为历史原因一直沿用至今,其实它真正表示的是 UTF-16 编码,更具体一点是 UTF-16小端,什么是大端和小端呢?

大端与小端

大小端是数据在存储器中的存放顺序,大端模式,是指数据的高字节在前,保存在内存的低地址中,与人类的读写法一致,数据的低字节在后,保存在内存的高地址中,小端与之相反,小端模式,是指数据的高字节在后,保存在内存的高地址中,而数据的低字节在前,保存在内存的低地址中例如,十六进制数值 0x1234567 的大端字节序和小端字节序的写法:

至于为什么会有大端和小端之分呢?对于 16 位或者 32 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节排放的问题,因为不同操作系统读取多字节的顺序不一样,,x86和一般的OS(如windows,FreeBSD,Linux)使用的是小端模式。但比如Mac OS是大端模式。因此就导致了大端存储模式和小端存储模式的存在,两者并没有孰优孰劣。

为什么UTF-8不需要考虑大小端问题?

UTF-8 的编码单元是1个字节,所以就不用考虑字节序问题。而 UTF-16 是用 2个字节来编码 Unicode 字符,编码单位是两个字节,因此需要考虑字节序问题,因为2个字节哪个存高位哪个存低位需要确定。

Python2 中的字符编码

现在总算把理论说完了,再来说说 Python 中的编码问题,也是每个Python开发者最关心、最经常遇到的问题,Python 的诞生时间比 Unicode 还要早几年,所以,Python的第一个版本一直延续到Python2.7,Python 的默认编码都是 ASCII
>>> import sys
>>> sys.getdefaultencoding()
'ascii'

所以在 Python 源代码,要能够正常保存中文字符就必须先指定utf

8 或者 gbk 格式
# coding=utf-8

或者是:

#!/usr/bin/python
# -*- coding: utf-8 -*-

str 与 unicode

在前面我们介绍过字符,这里还有必要重复一下字符和字节的区别,字符就是一个符号,比如一个汉字、一个字母、一个数字、一个标点都可以称为一个字符,而字节就是字符就是编码之后转换而成的二进制序列,一个字节是8个比特位。例如字符 "p" 存储到硬盘是一串二进制数据 01110000,占用一个字节。字节方便存储和网络传输,而字符用于显示方便阅读。

在Python2中,字符与字节的表示很微妙,两者的界限很模糊,Python2 中把字符串分为 unicode 和 str 两种类型。本质上 str 类型是二进制字节序列, unicode 类型的字符串是字符,下面的示例代码可以看出 str 类型的 "禅" 打印出来是十六进制的 \xec\xf8 ,对应的二进制字节序列就是 '11101100 11111000'。
>>> s = '禅'
>>> s
'\xec\xf8'
>>> type(s)
<type 'str'>

而 unicode 类型的 u"禅" 对应的 unicode 符号是 u'\u7985'
>>> u = u"禅"
>>> u
u'\u7985'
>>> type(u)
<type 'unicode'>

我们要把 unicode 字符保存到文件或者传输到网络就需要经过编码处理转换成二进制形式的 str 类型,于是 python 的字符串提供了 encode 方法,从 unicode 转换到 str,反之亦然。

>>> u = u"禅"
>>> u
u'\u7985'
>>> u.encode("utf-8")
'\xe7\xa6\x85'

>>> s = "禅"
>>> s.decode("utf-8")
u'\u7985'
>>>

不少初学者怎么也记不住 str 与 unicode 之间的转换用 encode 还是 decode,如果你记住了 str 本质上其实是一串二进制数据,而 unicode 是字符(符号),编码(encode)就是把字符(符号)转换为 二进制数据的过程,因此 unicode 到 str 的转换要用 encode 方法,反过来就是用 decode 方法。
引用
encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string".

清楚了 str 与 unicode 之间的转换关系之后,我们来看看什么时候会出现 UnicodeEncodeError、UnicodeDecodeError 错误。

UnicodeEncodeError

UnicodeEncodeError 发生在 unicode 字符串转换成 str 字节序列的时候,来看一个例子,把一串 unicode 字符串保存到文件
# -*- coding:utf-8 -*-
def main():
    name = u'Python之禅'
    f = open("output.txt", "w")
    f.write(name)

错误日志
引用
UnicodeEncodeError: 'ascii' codec can't encode characters in position 6-7: ordinal not in range(128)


为什么会出现 UnicodeEncodeError?

因为调用 write 方法时,程序会把字符经过编码转换成二进制字节序列,内部会有 unicode 到 str 的编码转换过程,程序会先判断字符串是什么类型,如果是 str,就直接写入文件,不需要编码,因为 str 类型的字符串本身就是一串二进制的字节序列了。如果字符串是 unicode 类型,那么它会先调用 encode 方法把 unicode 字符串转换成二进制形式的 str 类型,才保存到文件,而 Python2中,encode 方法默认使用 ascii 进行 encde.

相当于:
>>> u"Python之禅".encode("ascii")

但是,我们知道 ASCII 字符集中只包含了128个拉丁字母,不包括中文字符,因此 出现了 'ascii' codec can't encode characters 的错误。要正确地使用 encode ,就必须指定一个包含了中文字符的字符集,比如:UTF-8、GBK。
>>> u"Python之禅".encode("utf-8")
'Python\xe4\xb9\x8b\xe7\xa6\x85'

>>> u"Python之禅".encode("gbk")
'Python\xd6\xae\xec\xf8'

所以要把 unicode 字符串正确地写入文件,就应该预先把字符串进行 UTF-8 或 GBK 编码转换。
def main():
    name = u'Python之禅'
    name = name.encode('utf-8')
    with open("output.txt", "w") as f:
        f.write(name)

或者直接写str类型的字符串
def main():
    name = 'Python之禅'
    with open("output.txt", "w") as f:
        f.write(name)

当然,把 unicode 字符串正确地写入文件不止一种方式,但原理是一样的,这里不再介绍,把字符串写入数据库,传输到网络都是同样的原理

UnicodeDecodeError

UnicodeDecodeError 发生在 str 类型的字节序列解码成 unicode 类型的字符串时
>>> a = u"禅"
>>> a
u'\u7985'
>>> b = a.encode("utf-8")
>>> b
'\xe7\xa6\x85'
>>> b.decode("gbk")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'gbk' codec can't decode byte 0x85 in position 2: incomplete multibyte sequence

把一个经过 UTF-8 编码后生成的字节序列 '\xe7\xa6\x85' 再用 GBK 解码转换成 unicode 字符串时,出现 UnicodeDecodeError,因为 (对于中文字符)GBK 编码只占用两个字节,而 UTF-8 占用3个字节,用 GBK 转换时,还多出一个字节,因此它没法解析。避免 UnicodeDecodeError 的关键是保持 编码和解码时用的编码类型一致。

这也回答了文章开头说的字符 "禅",保存到文件中有可能占3个字节,有可能占2个字节,具体处决于 encode 的时候指定的编码格式是什么。

再举一个 UnicodeDecodeError 的例子
>>> x = u"Python"
>>> y = "之禅"
>>> x + y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>>

str 与 unicode 字符串 执行 + 操作时,Python 会把 str 类型的字节序列隐式地转换成(解码)成 和 x 一样的 unicode 类型,但Python是使用默认的 ascii 编码来转换的,而 ASCII字符集中不包含有中文,所以报错了。相当于:
>>> y.decode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

正确地方式应该是找到一种包含有中文字符的字符编码,比如 UTF-8或者 GBK 显示地把 y 进行解码转换成 unicode 类型
>>> x = u"Python"
>>> y = "之禅"
>>> y = y.decode("utf-8")
>>> x + y
u'Python\u4e4b\u7985'

Python3中的字符串与字节序列

Python3对字符串和字符编码进行了很彻底的重构,完全不兼容Python2,同时也很多想迁移到Python3的项目带来了很大的麻烦,Python3 把系统默认编码设置为 UTF-8,字符和二进制字节序列区分得更清晰,分别用 str 和 bytes 表示。文本字符全部用 str 类型表示,str 能表示 Unicode 字符集中所有字符,而二进制字节数据用一种全新的数据类型,用 bytes 来表示,尽管Python2中也有bytes类型,但那只不过是str的一个别名。
>>> a = "a"
>>> a
'a'
>>> type(a)
<class 'str'>

>>> b = "禅"
>>> b
'禅'
>>> type(b)
<class 'str'>


bytes

Python3 中,在字符引号前加‘b’,明确表示这是一个 bytes 类型的对象,实际上它就是一组二进制字节序列组成的数据,bytes 类型可以是 ASCII范围内的字符和其它十六进制形式的字符数据,但不能用中文等非ASCII字符表示。
>>> c = b'a'
>>> c
b'a'
>>> type(c)
<class 'bytes'>

>>> d = b'\xe7\xa6\x85'
>>> d
b'\xe7\xa6\x85'
>>> type(d)
<class 'bytes'>
>>>

>>> e = b'禅'
  File "<stdin>", line 1
SyntaxError: bytes can only contain ASCII literal characters.

bytes 类型提供的操作和 str 一样,支持分片、索引、基本数值运算等操作。但是 str 与 bytes 类型的数据不能执行 + 操作,尽管在python2中是可行的。
>>> b"a"+b"c"
b'ac'
>>> b"a"*2
b'aa'
>>> b"abcdef\xd6"[1:]
b'bcdef\xd6'
>>> b"abcdef\xd6"[-1]
214

>>> b"a" + "b"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str

python2 与 python3 字节与字符对比

总结
  • 字符编码本质上是字符到字节的转换过程
  • 字符集的演进过程是:ascii、eascii、ios8895-x,gb2312... Unicode
  • Unicode是字符集,对应的编码格式有UTF-8,UTF-16
  • 字节序列存储的时候有大小端之分
  • python2中字符与字节分别用unicode和str类型表示
  • python3中字符与字节分别用str与bytes表示
参考链接
  • 大小: 37.6 KB
  • 大小: 172.4 KB
  • 大小: 18.7 KB
  • 大小: 11.9 KB
  • 大小: 14.7 KB
  • 大小: 56.5 KB
  • 大小: 5.8 KB
来自: gitbook
2
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 基于JavaMail的邮件收发系统

    当用户重新安装操作系统或者更换计算机还要重新设置,而基于JavaMail的邮件收发系统的设置保存在邮件服务器上,不论你更换电脑还是系统,收发邮件的方式都是按照以前的设置进行的,使邮件的收发更合你的口味。...

  • James+Javamail构建邮箱服务

    1、SMTP(Simple Mail Transfer Protocol):即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。2、POP3(Post Office Protocol - Version 3):即邮局协议版本 3 ,...

  • java邮件中添加excel_基于javaMail的邮件发送--excel作为附件

    基于JavaMail的Java邮件发送Author xiuhong.chen@hand-china.comDesc 简单邮件发送Date 2017/12/8项目中需要根据物料资质的状况实时给用户发送邮件,然后我就简单学习了SMTP.电子邮件的在网络中传输和网页一样需要...

  • javaMail学习(四)——使用javaMail给网易账户发简单邮件

    代码跟上一篇的差不多,只需改变smpt的服务器地址和端口号。 package com.wjl.mail.utils; import java.security.GeneralSecurityException; import java.util.Properties; import javax.mail.Authenticator...

  • JavaMail通过IMAP和POP3接收未读以及设置已读邮件

    pop3和imap主要区别就是能否判断邮件状态的问题,其他的操作都差不多.   pop3收邮件和解析邮件: Java代码  package  com.clxx.test;    import  java.io....

  • java 发送附件_Java 基于javaMail的邮件发送(支持附件)

    基于JavaMail的Java邮件发送Author xiuhong.chen@hand-china.comDesc 简单邮件发送Date 2017/12/8项目中需要根据物料资质的状况实时给用户发送邮件,然后我就简单学习了SMTP.电子邮件的在网络中传输和网页一样需要...

  • 邮件发送javamail

     最近要将dms系统原始发邮件的功能(调用的webservice)改变成使用smtp服务来发送邮件(使用javamail来发送),这里简单记录下,方便日后有用到,直接拿来用即可。    首先导入需要用到的jar包:activation.jar ...

  • 借助javaMail来实现邮件的收发功能之知识篇

    1 电子邮件的需求  随着网络应用的不断推广,电子邮件越来越多的被大家使用。虽然我们往往将电子邮件与 Foxmail、Outlook这样的电子邮件客户端联系起来,但是往往在企业业务应用中我们也需要自己编程实现发送接收...

  • JavaMail

    建立JavaMail使用环境,需要哪些软件  首先,需要安装JavaMail API。现在有两种常用的 JavaMail API 版本:1.2 和 1.1.3。虽然版本 1.2 是最新版,但版本 1.1.3 包含了Java 2 平台企业版(Java 2 Platform, ...

  • James+Javamail构建邮件服务(四)

    5 Javamail邮件存储逻辑简介 5.1 Message存储结构示意图   Message是邮件发送的最终对象,我们一般使用他的子类对象MimeMessage,其子类对象里包含有邮件的MessageID、Subject、Flag、From、...

  • James+Javamail构建邮件服务

    James+Javamail构建邮件服务(一)    本文描述如何使用James搭建具备一定邮件过滤、邮件操作功能的邮件服务器,以及使用Javamail实现对James服务器邮件的收发功能。    1关于James与Javamail   Apache ...

  • javamail详解

    ...JavaMail API详解 cleverpig 发表于 2006-01-01 14:34:28 作者:cleverpig 来源:Matrix 摘要: JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eu

  • James(Java Apache Mail Enterprise Mail)+Javamail构建邮件服务

    James+Javamail构建邮件服务 James+Javamail构建邮件服务(一)    本文描述如何使用James搭建具备一定邮件过滤、邮件操作功能的邮件服务器,以及使用Javamail实现对James服务器邮件的收发功能。    ...

  • Java发送会议邮件 时区_关于java:在客户端/用户时区的电子邮件内容/正文中显示日期/时间/小时...

    它使用Spring和Freemarker从模板和Spring JavaMailSender发送电子邮件以发送它们。我在其内容中发送包含时间的电子邮件。 问题是服务器在UTC + 00时区存储时间,客户端可能有不同的时区,例如UTC + 03。 例如,在...

  • JavaMail 学习讲解

    JavaMail包中用于处理电子邮件的核心类是:Session,Message,Address,Authenticator,Store,Transport, Folder等。Session定义了一个基本的邮件会话,它需要从Properties中读取类似于邮件服务器,用户名和密码...

  • javamail总结(二) 电子邮件协议SMTP(转载)

    RFC821-简单邮件传输协议(SMTP)中文版1. 介绍 简单邮件传输协议(SMTP)的目标是可靠高效地传送邮件,它独立于传送子系统而且仅要求一条可以保证传送数据单元顺序的通道。附录A,B,C和D描述了不同传送服务下SMTP...

  • JavaMail详解

    JavaMail,顾名思义,提供给开发者处理电子邮件相关的编程接口。它是Sun发布的用来处理email的API。它可以方便地执行一些常用的邮件传输。我们可以基于JavaMail开发出类似于Microsoft Outlook的应用程序。 J...

  • 海尔智能电视刷机数据 U49A5 机编DH1W80A0305 务必确认机编一致 强制刷机 整机USB升级主程序

    务必确认机身编号与文件名机编一致,如不一致,请勿下载 机身编号一般在机子背面的贴纸上 升级方法: 1、下载数据,压缩包解压,将“Haier638Upgrade.bin”文件拷贝到U盘根目录下(U盘要求使用FAT32格式,建议4G-8G的品牌U盘,刷机成功率会高) 2、电视关机拔下电源,插入U盘,按住机身按键板上的“菜单”键不放,插电开机,直到LED灯开始闪表示升级正在进行,升级成功后机器会自动重起。 3、重启之后,重新交流上电,升级完成。 注意: 1、升级到结束,大约需要8-30分钟,中途绝对不能断电 2、升级重启第一次进入系统,请等完全正常进入开机桌面之后,才能拨下U盘

  • c语言c++项目源代码_c语言对自己电脑系统测试.rar

    **C语言电脑系统测试项目** 本项目是一个基于C语言的实用工具,旨在为您的电脑系统提供全面的性能测试与评估。通过执行一系列精心设计的测试用例,该工具能够评估您的电脑在处理器速度、内存管理、磁盘性能以及网络连接等方面的表现。 项目的核心功能包括: 1. **处理器性能测试**:通过执行复杂的算法和计算任务,评估处理器的运算速度和效率。 2. **内存测试**:检查内存分配、读写速度和稳定性,确保系统的内存管理达到最佳状态。 3. **磁盘性能测试**:评估硬盘或固态硬盘的读写速度、I/O性能和文件系统效率。 4. **网络性能测试**:测量网络连接的速度和稳定性,包括上传和下载速度以及延迟。 此外,该项目还提供了详细的测试报告功能,帮助您全面了解系统的优势和潜在瓶颈。测试结果以直观易懂的图表和数字形式呈现,便于分析和解读。 此项目采用模块化设计,方便您进行二次开发和定制,以满足特定需求。无论是硬件评测爱好者还是系统管理员,都能从该项目中受益良多。

  • pypy3.8-v7.3.6rc3-s390x.tar.bz2

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

Global site tag (gtag.js) - Google Analytics