6. 字符串和字节数组之间的转换
如果还想从 system.string 类中找到方法进行字符串和字节数组之间的转换,恐怕你会失望了。为了进行这样的转换,我们不得不借助另一个类:system.text.encoding。该类提供了 bye[] getbytes(string) 方法将字符串转换成字节数组,还提供了 string getstring(byte[]) 方法将字节数组转换成字符串。
system.text.encoding 类似乎没有可用的构造函数,但我们可以找到几个默认的 encoding,即 encoding.default(获取系统的当前 ansi 代码页的编码)、encoding.ascii(获取 7 位 ascii 字符集的编码)、encoding.unicode(获取采用 little-endian 字节顺序的 unicode 格式的编码)、encoding.utf7(获取 utf-7 格式的编码)、encoding.utf8(获取 utf-8 格式的编码) 等。这里主要说说 encoding.default 和 encoding.unicode 用于转换的区别。
在字符串转换到字节数组的过程中,encoding.default 会将每个单字节字符,如半角英文,转换成 1 个字节,而把每个双字节字符,如汉字,转换成 2 个字节。而 encoding.unicode 则会将它们都转换成两个字节。我们可以通过下列简单的了解一下转换的方法,以及使用 encoding.default 和 encodeing.unicode 的区别:
private void teststringbytes() {
string s = "c#语言";
byte[] b1 = system.text.encoding.default.getbytes(s);
byte[] b2 = system.text.encoding.unicode.getbytes(s);
string t1 = "", t2 = "";
foreach (byte b in b1) {
t1 += b.tostring("") + " ";
}
foreach (byte b in b2) {
t2 += b.tostring("") + " ";
}
this.textbox1.text = "";
this.textbox1.appendtext("b1.length = " + b1.length + "\n");
this.textbox1.appendtext(t1 + "\n");
this.textbox1.appendtext("b2.length = " + b2.length + "\n");
this.textbox1.appendtext(t2 + "\n");
}
运行结果如下,不说详述,相信大家已经明白了。
b1.length = 6
67 35 211 239 209 212
b2.length = 8
67 0 35 0 237 139 0 138
将字节数组转换成字符串,使用 encoding 类的 string getstring(byte[]) 或 string getstring(byte[], int, int) 方法,具体使用何种 encoding 还是由编码决定。在 teststringbytes() 函数中添加如下语句作为实例:
byte[] bs = {97, 98, 99, 100, 101, 102};
string ss = system.text.encoding.ascii.getstring(bs);
this.textbox1.appendtext("the string is: " + ss + "\n");
运行结果为:the string is: abcdef
7. 各种数值类型和字节数组之间的转换
在第 1 条中我们可以查到各种数值型需要使用多少字节的空间来保存数据。将某种数值类型的数据转换成字节数组的时候,得到的一定是相应大小的字节数组;同样,需要把字节数组转换成数值类型,也需要这个字节数组大于相应数值类型的字节数。
现在介绍此类转换的主角:system.bitconverter。该类提供了 byte[] getbytes(...) 方法将各种数值类型转换成字节数组,也提供了 toint32、toint16、toint64、touint32、tosignle、toboolean 等方法将字节数组转换成相应的数值类型。
由于这类转换通常只是在需要进行较细微的编码/解码操作时才会用到,所以这里就不详细叙述了,仅把 system.bitconverter 类介绍给大家。
8. 转换成十六进制
任何数据在计算机内部都是以二进制保存的,所以进制与数据的存储无关,只与输入输出有关。所以,对于进制转换,我们只关心字符串中的结果。
在上面的第 4 条中提到了 tostring() 方法可以将数值转换成字符串,不过在字符串中,结果是以十进制显示的。现在我们带给它加一些参数,就可以将其转换成十六进制——使用 tostring(string) 方法。
这里需要一个 string 类型的参数,这就是格式说明符。十六进制的格式说明符是 "x" 或者 "x",使用这两种格式说明符的区别主要在于 a-f 六个数字:"x" 代表 a-f 使用小写字母表示,而 "x" 而表示 a-f 使用大字字母表示。如下例:
private void testhex() {
int a = 188;
this.textbox1.text = "";
this.textbox1.appendtext("a(10) = " + a.tostring() + "\n");
this.textbox1.appendtext("a(16) = " + a.tostring("x") + "\n");
this.textbox1.appendtext("a(16) = " + a.tostring("x") + "\n");
}
运行结果如下:
a(10) = 188
a(16) = bc
a(16) = bc
这时候,我们可能有另一种需求,即为了显示结果的整齐,我们需要控制十六进制表示的长度,如果长度不够,用前导的 0 填补。解决这个问题,我们只需要在格式说明符“x”或者“x”后写上表示长度的数字就行了。比如,要限制在 4 个字符的长度,可以写成“x4”。在上例中追加一句:
this.textbox1.appendtext("a(16) = " + a.tostring("x4") + "\n");
其结果将输出 a(16) = 00bc。
现在,我们还要说一说如何将一个表示十六进制数的字符串转换成整型。这一转换,同样需要借助于 parse() 方法。这里,我需要 parse(string, system.globalization.numberstyles) 方法。第一个参数是表示十六进制数的字符串,如“ab”、“20”(表示十进制的 32) 等。第二个参数 system.globalization.numberstyles 是一个枚举类型,用来表示十六进制的枚举值是 hexnumber。因此,如果我们要将“ab”转换成整型,就应该这样写:int b = int.parse("ab", system.globalization.numberstyles.hexnumber),最后得到的 b 的值是 171。
9. 日期型数据和长整型数据之间的转换
为什么要将日期型数据转换为长整型数据呢?原因很多,但就我个人来说,经常将它用于数据库的日期存储。由于各种数据库对日期型的定义和处理是不一样的,各种语言对日期型数据的定义的处理也各不相同,因为,我宁愿将日期型数据转换成长整型再保存到数据库中。虽然也可以使用字符串来保存,但使用字符串也会涉及到许多问题,如区域等问题,而且,它需要比保存长整型数据更多的空间。
日期型数据,在 c# 中的参与运算的时候,应该也是转换为长整型数据来运算的。它的长整型值是自 0001 年 1 月 1 日午夜 12:00 以来所经过时间以 100 毫微秒为间隔表示时的数字。这个数在 c# 的 datetime 中被称为 ticks(刻度)。datetime 类型有一个名为 ticks 的长整型只读属性,就保存着这个值。如此,要从一个 datatime 型数据得到 long 型值就非常简单了,只需要读出 datatime 对象的 ticks 值即可,如:
long longdate = datetime.now.ticks;
datetime 的构造函数中也提供了相应的,从长整型数据构造 datetime 型数据的函数:datetime(long)。如:
datetime thedate = new datetime(longdate);
但这样对于很多 vb6 程序员来说,是给他们出了一道难题,因为 vb6 中的日期型数据内部是以 double 型表示的,将其转换为长整型后得到的仅仅是日期,而没有时间。如何协调这两种日期类型呢?
system.datetime 提供了 double tooadate() 和 static datetime fromoadate(double) 两个函数来解决这个问题。前者将当前对象按原来的 double 值输出,后者则从一个 double 值获得一个 system.datetime 对象。举例如下:
private void testdatetimelong() {
double doubledate = datetime.now.tooadate();
datetime thedate = datetime.fromoadate(doubledate);
this.textbox1.text = "";
this.textbox1.appendtext("double value of now: " + doubledate.tostring() + "\n");
this.textbox1.appendtext("datetime from double value: " + thedate.tostring() + "\n");
}
运行结果:
double value of now: 37494.661541713
datetime from double value: 2002-8-26 15:52:37