郝 偉
XML(Extensible Markup Language)即可擴(kuò)展標(biāo)記語言,它與HTML一樣,都是SGML(Standard Generalized Markup Language,標(biāo)準(zhǔn)通用標(biāo)記語言),即使用標(biāo)記對內(nèi)容進(jìn)行區(qū)分。由于Xml是Internet環(huán)境中跨平臺的,依賴于內(nèi)容的技術(shù),是當(dāng)前處理結(jié)構(gòu)化文檔信息的有力工具[1]。
由于XML使用了大量的標(biāo)記符,所以使用XML會(huì)占用更多的空間,但由于XML極其簡單易于掌握和使用,加上現(xiàn)在硬件技術(shù)和軟件水平的不斷發(fā)揮,所以XML已經(jīng)廣泛應(yīng)用于數(shù)據(jù)庫技術(shù)和網(wǎng)絡(luò)傳輸中[2]。
圖形和圖片在Internet中,是最常見到的文件格式,圖片都是使用二進(jìn)制進(jìn)行存儲(chǔ),所以如果在基于文本的XML文件中傳輸?shù)脑?,就很可能是破壞XML的內(nèi)容。如,在二進(jìn)制數(shù)據(jù)中,如果正好包含 “<>”這樣的標(biāo)記,原XML文件的內(nèi)容就很可能會(huì)被破壞,接收端就無法正確的解析XML數(shù)據(jù),從而造成數(shù)據(jù)傳輸?shù)氖?,所以一般圖片都是與文本分開傳輸?shù)?。然而?shù)據(jù)分開傳輸雖然能解決問題,但是傳輸?shù)慕y(tǒng)一性就會(huì)被破壞,而且存儲(chǔ)也需要在不同的空間完成,對于一些有一定安全性要求的場合就會(huì)不太適用。
筆者在之前的文章中已經(jīng)提出了一種算法《一種基于XML的圖像存儲(chǔ)方法》,已經(jīng)初步解決了這個(gè)問題,但是所使用的方法沒有充分考慮效率,平均每一個(gè)碼元會(huì)增加大量的冗余數(shù)據(jù),所以當(dāng)前的問題是進(jìn)一步提高轉(zhuǎn)換效率,從而適應(yīng)提高傳輸效率。
現(xiàn)在各類壓縮和加密算法很多,但是全都是基于二進(jìn)制的,即都是取字節(jié)0-255的所有段來進(jìn)行的,這些段時(shí),除了包括數(shù)字,大小寫字母,標(biāo)點(diǎn)符號這些可見元素,還包括一些非可見的控件符,如回車,退格,表格等,同時(shí)還有一定幾率包括一些XML的關(guān)鍵字和XML標(biāo)記的左右括號等,所以使用XML進(jìn)行傳輸可能會(huì)出現(xiàn)一定的問題。因此現(xiàn)有的加密算法不能解決這個(gè)問題[3]。
解決這個(gè)問題最關(guān)鍵的就是將圖片中的所有二進(jìn)制轉(zhuǎn)換為可識別的二進(jìn)制,即可以使用ASCII正常表示的,可以選用的包括大小寫字母和數(shù)字。
在《一種基于XML的圖像存儲(chǔ)方法》一文中,所提出的方法是使用的是2個(gè)字節(jié)表示一個(gè)二進(jìn)制碼的辦法,從而使一個(gè)字節(jié)變成了2個(gè)字符的表示方式,而在長度上,其容量增加了一倍。如果在大量的數(shù)據(jù)傳輸,那么增加的一倍會(huì)降低傳輸效率,同時(shí)也會(huì)導(dǎo)致數(shù)據(jù)傳輸時(shí)間的加長[4]。
因此,本方提出了一種新方法,減少轉(zhuǎn)換后的數(shù)據(jù)量,從而增加傳輸效率。由于二進(jìn)制中可顯示的碼元有限,常見的只有48-59,65-90,97-122這62的可用碼元。要表示一個(gè)字節(jié)的二進(jìn)制完全是不夠的。
由于3個(gè)可見碼元空間是62*62*62 = 238328>65536=256*256,所以可以采取用3個(gè)可見碼元表示2個(gè)二進(jìn)制數(shù)據(jù)的方法,從而減少了冗余數(shù)據(jù)量。
另外,由于52個(gè)碼元的效果和62的碼元的效果在減少碼元長度上并沒有區(qū)別,因?yàn)?個(gè)52進(jìn)制編碼所表示的范圍是:52*52*52=140608>65536,即三個(gè)52進(jìn)制的碼元是可以完全包括4位16進(jìn)制編碼三元的,所以從簡化的角度出發(fā),只使用大小寫字母的52個(gè)碼元,不再使用數(shù)數(shù)字。當(dāng)然,如果仍然使用數(shù)據(jù)除了計(jì)算上略有影響,與只使用字母沒有任何區(qū)別。
將圖片文件中的數(shù)據(jù)的每個(gè)字節(jié)轉(zhuǎn)換成可識別的ASCII碼,本方法將2字節(jié)二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為3的52進(jìn)制編碼,計(jì)算方法如下:
1)設(shè)2字節(jié)的二進(jìn)制編碼為B1 B2,那么可以計(jì)算出其對應(yīng)的十進(jìn)制編碼
D10 =B1*256+B2。 (D表示10進(jìn)制編碼,B1表示原碼高位,B2表示原碼低位)
2)將十進(jìn)制轉(zhuǎn)換為52進(jìn)制,轉(zhuǎn)換方法采取余的方式,轉(zhuǎn)換后會(huì)有三位52進(jìn)制碼,轉(zhuǎn)換公式如下:
bl = D10 % 52(bl表示低位)
bm = (D10 / 52) % 52 (bm表示中間位)
bh = (D10 / 52) / 52(bh表示高位)
3)將52進(jìn)制轉(zhuǎn)換為對應(yīng)的大小寫字母,轉(zhuǎn)換方法如下:
C = C + 65 C∈[0, 25]
C + 97 - 26 C∈[26, 51]
4)將交換好的值,用對應(yīng)的ASCII碼表示。
即0-65535對應(yīng)三位的大小寫字母,如00 00對應(yīng)AAA,F(xiàn)F FF 對應(yīng)XLO。根據(jù)以上原理編,下面筆者使用程序語言進(jìn)行編程,以對設(shè)計(jì)結(jié)果進(jìn)行驗(yàn)證(以下代碼均以C#代碼為例)。
二進(jìn)制的數(shù)據(jù)是以字節(jié)數(shù)據(jù)的進(jìn)行讀取過來,然后傳遞到程序中進(jìn)行數(shù)據(jù)處理,所使用的數(shù)據(jù)轉(zhuǎn)換程序如下所示。
//用于編碼的函數(shù)
public string Encode(byte[] bts)
{
//建立變長數(shù)組,用于保存數(shù)據(jù)
StringBuilder builder = new StringBuilder();
int len = bts.Length / 2;
for (int i = 0; i < len; i++)
{
int t = bts[i] * 256 + bts[i + 1];
int v0 = t % 52;
t = t / 52;
int v1 = t % 52;
t = t / 52;
int v2 = t;
builder.Append(Transfer(v0));
builder.Append(Transfer(v1));
builder.Append(Transfer(v2));
}
return builder.ToString();
}
private string Transfer(int v)
{
v = v < 26 ? v + 65 : v + 97 - 26;
return ((char)v).ToString();
}
轉(zhuǎn)換時(shí)先轉(zhuǎn)換成52進(jìn)制的編碼,然后再根據(jù)0-25轉(zhuǎn)換成A-Z,26-51轉(zhuǎn)換成a-z的規(guī)則,將所有轉(zhuǎn)換好的數(shù)值轉(zhuǎn)換成字母。
加密后的數(shù)據(jù)以字符串的形式存在,讀取后傳遞到程序中進(jìn)行數(shù)據(jù)處理,所使用的數(shù)據(jù)轉(zhuǎn)換程序如下所示。
//用于解碼的函數(shù)。
public byte[] Decode(string s)
{
//建立用于保存二進(jìn)制數(shù)據(jù)的數(shù)組。
byte[] bts = new byte[s.Length % 3];
int length = s.Length / 3;
//循環(huán)控制,
for (int i = 0; i < length; i++)
{
int t = Transfer1(s[i]) +
Transfer1(s[i + 1]) * 52 +
Transfer1(s[i + 2]) * 52 * 52;
bts[i] = (byte)(t / 256);
bts[i + 1] = (byte)(t % 256);
}
return bts;
}
private int Transfer1(char c)
{
int v = (int)c;
return v > 90 ? v - 97 + 32 : v - 65;
}
三位字符對應(yīng)的值為A-Z對應(yīng)0-25,a-z對應(yīng)26-51,轉(zhuǎn)換好以的三位a1,a2,a3再按照以下公式進(jìn)行計(jì)算,從而還原原來的值。
計(jì)算公式為原先公式的逆運(yùn)行,分為以下幾步:
1)將大小寫字母轉(zhuǎn)換成52進(jìn)制的數(shù)據(jù)。
2)將52進(jìn)制的數(shù)據(jù)轉(zhuǎn)換為10進(jìn)制,公式為
b = a3*52*52 + a2 * 52 + a1,其中b為原值。
3)將10進(jìn)制轉(zhuǎn)換為二進(jìn)制
從原始的二進(jìn)制的數(shù)據(jù)里可以看到,原始數(shù)據(jù)中里包含著如“<”, “>”等大量這樣的非字符碼元,這些非法碼元的存在有著很大的安全隱患,很可能會(huì)導(dǎo)致整個(gè)XML數(shù)據(jù)模塊的解析失敗,從而使原有XML文件的相關(guān)數(shù)據(jù)被二進(jìn)制編碼所破壞。
現(xiàn)在采取將《一種基于XML的圖像存儲(chǔ)方法》一文中的方法將其轉(zhuǎn)換后,以小寫字母和數(shù)字的形式出現(xiàn),重新編碼后的XML文件如下所示。這樣經(jīng)過編碼以后,再使用XML就不會(huì)出現(xiàn)任何問題,但是長度比較度,為原來長度的2倍。于是采取本方中的新的編碼方式,結(jié)果如下所示。
經(jīng)過編碼以后,XML的傳輸就不會(huì)出現(xiàn)任何問題,但是長度比較度,為原來長度的2倍。在采取本方中的新的編碼方式,結(jié)果如下所示。
采用新的編碼以后,碼元的長度大大減少,達(dá)到了預(yù)期的目的。
本方提出了一種方法,將二進(jìn)制的圖片轉(zhuǎn)換為可識別的字符串的,從而實(shí)現(xiàn)了在XML中傳輸圖片。同時(shí)采用新的算法,較《一種基于XML的圖像存儲(chǔ)方法》一文中的方法大幅提高了算法的效率,兼顧了效率,減少了存儲(chǔ)的容量,提高了傳輸效率。
[參 考 文 獻(xiàn)]
[1] 郝 偉.一種基于XML的圖像存儲(chǔ)方法[J].電腦技術(shù)與應(yīng)用, 2011(5).
[2] Steve Holzner. Inside XML[M].WROX PR,2000.
[3] Andrew Troelsen. Advcenced C# & .NET Program Design 4.0[M].北京:人民郵電出版社,2010.
[4] 李家同.算法設(shè)計(jì)與分析導(dǎo)論[M].北京:機(jī)械工業(yè)出版社,2008.
[5] 呂國英.算法設(shè)計(jì)與分析(第2版)[M]. 北京:清華大學(xué)出版社,2009.