What's the most standard Java way to store raw binary data along with XML?

前端 未结 4 745
予麋鹿
予麋鹿 2020-12-31 21:13

I need to store a huge amount of binary data into a file, but I want also to read/write the header of that file in XML format.

Yes, I could just store the binary

4条回答
  •  执笔经年
    2020-12-31 22:02

    I followed the concept suggested by Blaise Doughan, but without attachment marshallers:

    I let an XmlAdapter convert a byte[] to a URI-reference and back, while references point to separate files, where raw data is stored. The XML file and all binary files are then put into a zip.

    It is similar to the approach of OpenOffice and the ODF format, which in fact is a zip with few XMLs and binary files.

    (In the example code, no actual binary files are written, and no zip is created.)

    Bindings.java

    import java.net.*;
    import java.util.*;
    import javax.xml.bind.annotation.*;
    import javax.xml.bind.annotation.adapters.*;
    
    final class Bindings {
    
      static final String SCHEME = "storage";
      static final Class[] ALL_CLASSES = new Class[]{
        Root.class, RawRef.class
      };
    
      static final class RawRepository
          extends XmlAdapter {
    
        final SortedMap map = new TreeMap<>();
        final String host;
        private int lastID = 0;
    
        RawRepository(String host) {
          this.host = host;
        }
    
        @Override
        public byte[] unmarshal(URI o) {
          if (!SCHEME.equals(o.getScheme())) {
            throw new Error("scheme is: " + o.getScheme()
                + ", while expected was: " + SCHEME);
          } else if (!host.equals(o.getHost())) {
            throw new Error("host is: " + o.getHost()
                + ", while expected was: " + host);
          }
    
          String key = o.getPath();
          if (!map.containsKey(key)) {
            throw new Error("key not found: " + key);
          }
    
          byte[] ret = map.get(key);
          return Arrays.copyOf(ret, ret.length);
        }
    
        @Override
        public URI marshal(byte[] o) {
          ++lastID;
          String key = String.valueOf(lastID);
          map.put(key, Arrays.copyOf(o, o.length));
    
          try {
            return new URI(SCHEME, host, "/" + key, null);
          } catch (URISyntaxException ex) {
            throw new Error(ex);
          }
        }
    
      }
    
      @XmlRootElement
      @XmlType
      static final class Root {
    
        @XmlElement
        final List element = new LinkedList<>();
      }
    
      @XmlType
      static final class RawRef {
    
        @XmlJavaTypeAdapter(RawRepository.class)
        @XmlElement
        byte[] raw = null;
      }
    
    }
    

    Main.java

    import java.io.*;
    import javax.xml.bind.*;
    
    public class _Run {
    
      public static void main(String[] args)
          throws Exception {
        JAXBContext context = JAXBContext.newInstance(Bindings.ALL_CLASSES);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        Unmarshaller unmarshaller = context.createUnmarshaller();
    
        Bindings.RawRepository adapter = new Bindings.RawRepository("myZipVFS");
        marshaller.setAdapter(adapter);
    
        Bindings.RawRef ta1 = new Bindings.RawRef();
        ta1.raw = "THIS IS A STRING".getBytes();
        Bindings.RawRef ta2 = new Bindings.RawRef();
        ta2.raw = "THIS IS AN OTHER STRING".getBytes();
    
        Bindings.Root root = new Bindings.Root();
        root.element.add(ta1);
        root.element.add(ta2);
    
        StringWriter out = new StringWriter();
        marshaller.marshal(root, out);
    
        System.out.println(out.toString());
      }
    
    }
    

    Output

    
        
            storage://myZipVFS/1
        
        
            storage://myZipVFS/2
        
    
    

提交回复
热议问题