|
XML中二进制数据的处理方法
在xml中,所有的数据都是以文本的形式来显示,但是二进制数据不能直接以文本格式来表示,那xml又是怎么处理二进制数据的呢?下面就来探讨一下。
为了简单和通用性,xml被设计成了以文本的格式来表示数据。在xml中,所有的数据都是以文本的格式来存储,二进制数据也不例外。在xml中,二进制数据也要被编码成文本的格式,发送到目的方。目的方接收到这个文本二进制数据以后,再以相同的解码程序解成相应的二进制数据,当然数据原来的格式,名称等辅助信息一定要当作相关信息一起发送。一般二进制数据编码成BASE64格式,它的优点是容易易于编码和解码,缺点是比纯的二进制多占用33%的存储空间。
下面是具体的程序实现:
<%@ page contentType="text/html; charset=gb2312" %>
<%@ page import="java.io.*" %>
<%
String ret=new String();
try
{
InputStream in=new FileInputStream("c:\\aaa.doc");
byte[] bytes=new byte[in.available()];
in.read(bytes);
ret=new sun.misc.BASE64Encoder().encode(bytes); //具体的编码方法
in.close();
}
catch(FileNotFoundException e)
{
e.printStackTrace();
}
catch(java.io.IOException ex)
{
ex.printStackTrace();
}
%>
ret就是最后的结果,编码以后就可以用标准的xml方式发送了。发送到目的方以后,还要对数据进行相应的解码,才能得到原来的二进制文件,解码的代码如下:
<%@ page contentType="text/html; charset=gb2312" %>
<%@ page import="java.io.*" %>
<%
byte[] bytes = new sun.misc.BASE64Decoder().decodeBuffer(ret);
java.io.ByteArrayInputStream inStream=new java.io.ByteArrayInputStream(bytes);
byte[] buffer =new byte[1444];
FileOutputStream fs=new FileOutputStream( "d:\\aaa.doc");
int bytesum=0;
int byteread=0;
while ((byteread=inStream.read(buffer))!=-1)
{
bytesum+=byteread;
fs.write(buffer,0,byteread);
}
%>
BASE64可以处理不太大的数据,如果要移动大量的数据,且要考虑空间/时间效率时,要采用其他的替代方法。
XML文档的优点之一是它的可阅读性,无论是机器还是人都可以将它读懂,因此它的字符是要遵循一定的规则的。对于一般的信息资料,用XML标记将其表达清楚,并不是什么困难的事,但对于一些特殊的行业,有些事就让人有些头疼了。比如在印刷行业,处理大数据量的图象文件可谓是家常便饭,医疗行业也有类似的情况,如X光图象、CT图象等,而对于一些多媒体行业而言,不仅有视频图象数据,还有音频数据。这些数据一般都是以二进制的数据格式存储,人是读不懂的,不能直接将其放入XML文件中,被称之为非XML数据。
使用HTML的经验告诉我们,将这种文件甩在HTML/XML文件之外是一个可行的方法,如使用<img>标记,只引用图象文件的存储地址,解释器解释出这是一个图象资源后,再将整个图象数据调入并显示。这种方法对于经常要进行数据传输的一些应用来讲并不是很适用,试想如果一个XML文件中包含了很多个图象文件,在将XML文件进行传输时要达到一个不少的将其所含的外部文件统统传递过去,实在是个很困难的事。而且有时人们还是希望能够将这些二进制数据直接嵌进XML文档中。如何做到这一点呢?归结起来大概有三种方法:
1. 使用CDATA
大家知道,在XML文件中,使用CDATA类型,可以将一些不希望解释器解释的数据放在其保护伞之下。理论上,对于二进制数据来讲,用这种方法混进XML文档也是一条路。但是对于CDATA包含的数据,解释器在解释时要查找"]]>"作为CDATA的结束标记,有时二进制编码很长,所有的数据都要参与字符串查找,很显然效率不会很高,而且会出现一些其它的问题,因此,这种方式很少使用,只是一种理论上的说法。
2. 编码转换
顾名思义,这种方法将二进制数据进行编码,使之具有字符形态,就可以名正言顺地进入到XML文档中去了。一般将其用Base64编码,编码后的二进制文件就成了字符形态。仅仅是这样编码也还会出现问题,诸如"<"的标记专用问题,会给解释器带来问题,而且还需要有个标志告诉解释器,这是二进制数据,要解码后使用。针对这个问题XML-Data提出了一个解决方法,就是使用"dt"属性,将转换后的数据流描述成为:
<stuff dt:dt="binary.base64">84592gv8Z5Zb82bA68g</stuff>
这样,数据流就有了自描述性,解释器可以正确地解释该段代码了。
编码转换的方法不失为一种较好的解决方法,但对于大数据量的数据而言,并不是一种非常有效的方法,编码和解码是要有代价的,下面我们介绍一种被广泛用于图象处理和多媒体的解决方法。
3. 使用MIME
MIME标准最初是用于eMail的信息传输的,这种信息不仅仅是ASCII码,各种编码都会遇到。借用MIME的特性,我们可以达到将二进制数据嵌入到XML文档中的目的。 ]
实现方式是这样的,在XML文件中使用MIME的分隔符替代起始和终止标记,将数据放在其中。解释器发现是MIME数据流,就将其中的数据按MIME方式解码处理。下面我们来看一个SMIL(同步多媒体综合语言)使用MIME传递二进制数据的例子。
在SMIL多是描述音频和视频数据,99.9%的数据都不是字符,它即可以将文件名放在文档中,也可以用MIME的方法将数据直接包含在SMIL文档中。例一是引用文件名的例子,例二是直接包含数据的例子。
例一:
<smil>
< head>
< switch>
< layout type="text/css">
[region="r"] { top: 20px; left: 20px }
#i2 { top: 30px; left: 30px }
< /layout>
< layout>
< region id="r" top="20" left="20" />
< /layout>
< /switch>
< /head>
< body>
< seq>
< img region="r" src="http://.../test" dur="10s"/>
< img id="i2" src="http://.../test2" dur="5s" />
< /body>
< /smil>
例二:
Content-Type: multipart/related;
boundary="--- part separator"
--- part separator Content-Type: text/smil
Content-ID: smil-message
< smil>
...
< body>
< seq>
< img region="r" src="cid:test" dur="10s" />
< img id="i2" src="cid:test2" dur="5s" />
< /seq>
< /body>
< smil>
---part separator
Content-Type: application/jpeg
Content-ID: test
... jpeg数据
---part separator
Content-Type: application/gif
Content-ID: test2
... gif数据
---part separator
综上所述,将二进制数据嵌入到XML文件中有不同的方法,具体哪一种方法更好,还要看具体的应用情况,希望在不久的将来,我们能看到W3C对这个问题所给出的明确答案。 |
|