利用Base64在XML中存储BLOB

来源:互联网 发布:qq安全中心mac版 编辑:程序博客网 时间:2024/05/30 23:12
在一些 XML 的应用中,例如 SOAP,除了复杂的数据类型外,还可能包括图像、声音等多媒体数据。通常的处理办法是通过序列化的Java对象为载体进行传输,或者将图像、声音等数据包含在外部实体中,如果能将这些大型二进制对象存储在XML文件中,则处理起来会有很大的便利性。

这里我们将以图像为例子讨论在 XML 中存储传输 BLOB 数据的方法。
Base64算法详解
Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。如例1所示:

字符串“张3”
11010101   11000101    00110011

转换成Base64

00110101   00011100     00010100     00110011

即把8位的字节连成一串110101011100010100110011 然后每次顺序选6个出来之后再把这6二进制数前面再添加两个0,就成了一个新的字节。之后再选出6个来,再添加0,依此类推,直到24个二进制数全部被选完。

让我们来看看实际结果:

11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33
00110101 00011100 00010100 00110011
字符’5′ 字符’^’ 字符’^T’ 字符’3′
十进制53 十进制34 十进制20 十进制51

但是 Base64 编码方式并不是单纯利用转化完的内容进行编码。像’^’字符是控制字符,并不能通过计算机显示出来,在某些场合就不能使用了。Base64 有其自身的编码表:

00-25   "A-Z"  
26-51   "a-z"    
52-61  " 0-9"    
62       "+"
63       "/"  
(pad)   "="

表中,编码的编号对应的是得出的新字节的十进制值。因此,可以得到对应的 Base64 编码:

字符串“张3”
11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33
00110101     00011100    00010100    00110011
字符’5′           字符’^’         字符’^T’        字符’3′
十进制53     十进制34      十进制20    十进制51
字符’1′           字符’i’           字符’U’       字符’z’

这样字符串“张3”经过编码后就成了字符串“1iUz”了。Base64 将3个字节转变为4个字节,因此,编码后的代码量(以字节为单位,下同)约比编码前的代码量多了1/3。

在The Base64 Alphabet中的最后一个有一个(pad) =字符。这个字符的目的就是用来处理下面这个问题的:

当代码量不是3的整数倍时,代码量/3的余数自然就是2或者1。转换的时候,结果不够6位的用0来补上相应的位置,之后再在6位的前面补两个0。转换完空出的结果就用就用“=”来补位。

譬如结果若最后余下的为2个字节的“张”:

字符串“张”
11010101 HEX:D5 11000101 HEX:C5
00110101     00011100      00010100
十进制53     十进制34      十进制20 pad
字符’1′          字符’i’          字符’U’ 字符’=’

这样,最后的2个字节被整理成了“1iU=”。
同理,若原代码只剩下一个字节,那么将会添加两个“=”。只有这两种情况,所以,Base64的编码最多会在编码结尾有两个“=”

使用 BASE64 编码传输 BLOB 数据
下面我们结合图形存储来看具体的编程实现。这里使用的 Base64 编码器是开源软件,你可以在http://iharder.sourceforge.net/base64/下载。

packagecc.ejb.examples;
import cc.ejb.util.base64.Base64;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Image2Xml {

    private final static String XML_DOC_HEADER = "<?xml version="1.0" ?>n";
    public Image2Xml(){ }
    public static void main(String[] args){
        Image2Xml processor=new Image2Xml();
        try
        {
            processor.convert("music_inside.jpg","musicInsideBase64.xml");
            processor.recover("musicInsideBase64.xml","music_inside.jpg");
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }
   
    private byte[] readBinaryFile(String filename) throws IOException
    {
      File file = new File(filename);
      BufferedInputStream bis = new BufferedInputStream(new
        FileInputStream(file));
      int bytes = (int) file.length();
      byte[] buffer= new byte[bytes];
      int readBytes = bis.read(buffer);
      bis.close();
      System.out.println("Read "+ readBytes + " and expected to read " + bytes);
      return buffer;
    }
    public void convert(String imageFilename,String outXmlFilename) {

        try {
          byte[] buffer= readBinaryFile(imageFilename);
          int readBytes = buffer.length;

          long startTime = (new java.util.Date()).getTime();
          StringBuffer strXMLDoc = new StringBuffer(XML_DOC_HEADER);
          strXMLDoc.append("<image name=""+ imageFilename + "">");
          String encodedString = Base64.encodeBytes(buffer,Base64.GZIP);
          strXMLDoc.append(encodedString);
          strXMLDoc.append("</image>");
          long endTime = (new java.util.Date()).getTime();
          long diffTime = endTime- startTime;
          System.out.println("Total conversion time for "+ readBytes + " was " +
            diffTime + " msec or "+ ((double) readBytes)/((double) diffTime) + " bytes/msec.");

          writeXmlFile(outXmlFilename, strXMLDoc.toString());
        } catch (IOException e){
          System.out.println("Our exception is: "+ e);
        }
    }
    private void writeXmlFile(String filename,String data) throws IOException
    {
      File file = new File(filename);
      BufferedOutputStream bos = new BufferedOutputStream(new
        FileOutputStream(file));
      bos.write(data.getBytes());
      bos.close();

      System.out.println("Wrote "+ data.getBytes().length+ " to file " + filename);
      return;
    }
   
    private Document readXmlFile(String xmlFilename)throws SAXException,ParserConfigurationException,IOException
    {
           Document doc=null;
               DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
               factory.setValidating(false);
               factory.setNamespaceAware(false);
               DocumentBuilder builder = factory.newDocumentBuilder();
               doc = builder.parse(xmlFilename);
               return doc;
    }
    public void recover(String xmlFilename,String imageFilename) throws SAXException,ParserConfigurationException,IOException
    {
      Document doc=readXmlFile(xmlFilename);
      NodeList list = doc.getElementsByTagName("image");
      Node item = list.item(0);
      long startTime = (new java.util.Date()).getTime();
      StringBuffer imageData=newStringBuffer(list.item(0).getChildNodes().item(0).getNodeValue());
      byte[] buffer=Base64.decode(imageData.toString());
      double readBytes = buffer.length;
      double totalChars = imageData.toString().length();
      System.out.println("Encoded "+ readBytes + " bytes using " +
          totalChars + " characters for an average length of "+
          totalChars/readBytes +" characters.");
      writeBinaryFile(imageFilename,buffer);
    }
    private  void writeBinaryFile(String filename,byte[] buffer) throws IOException
    {
            File file = new File(filename);
            BufferedOutputStream bos = new BufferedOutputStream(newFileOutputStream(filename));
            bos.write(buffer);
            bos.close();
    }
 
}


原创粉丝点击