Java uses bytearrayoutputstream and bytearrayinputstream to avoid repeatedly reading configuration files _java

Source: Internet
Author: User
Tags getmessage

The Bytearrayoutputstream class is a buffer in which a byte array is created inside the program when an instance of it is created. The byte data is then written to or read out of the array using instances of Bytearrayoutputstream and Bytearrayinputstream. In the network transmission we often have to transfer a lot of variables, we can use Bytearrayoutputstream to collect all the variables together, and then send the data once. The specific usage is as follows:

Bytearrayoutputstream: Data from memory buffers can be captured and converted into byte arrays.

Bytearrayinputstream: You can convert a byte array into an input stream

The Bytearrayinputstream class has two default constructors:

Bytearrayinputstream (byte[] b): Use all the data in a byte array as a data source, the program can read bytes like the input stream, can be seen as a virtual file, file to read the data inside it.

Bytearrayinputstream (byte[] b,int offset,int length): Start with offset in the array, and take the length of this byte as the data source.

The Bytearrayoutputstream class also has two default constructors:

Bytearrayoutputstream (): Creates a 32-byte buffer
Bytearrayoutputstream (int): Creates a buffer based on the specified size of the parameter

Recently participated in an open source project on GitHub Mycat, is a MySQL repository of the middleware of the sub-table. found that the code read the configuration file, there are frequent repeated open, read, shut down the problem, the code written very early, a little read some framework source code, is not make such a mistake. Some optimizations were made to it.

The code before the optimization looks like this:

private static Element Loadroot () {
  InputStream DTD = null;
  InputStream xml = null;
  Element root = null;
  try {
    DTD = ConfigFactory.class.getResourceAsStream ("/mycat.dtd");
    XML = ConfigFactory.class.getResourceAsStream ("/mycat.xml");
    Root = Configutil.getdocument (DTD, XML). Getdocumentelement ();
  catch (Configexception e) {
    throw e;
  } catch (Exception e) {
    throw new configexception (e);
  } finally { C13/>IF (DTD!= null) {
      try {
        dtd.close ();
      } catch (IOException e) {}
    }
    if (XML!= null) {
      try {
        xml.close ();
      } catch (IOException e) {}} return
  root;

Then other methods frequently invoke Loadroot ():

@Override public
userconfig getuserconfig (String user) {
  Element root = Loadroot ();
  Loadusers (root);
  return This.users.get (user);
}
@Override public
map<string, userconfig> getuserconfigs () {
  Element root = Loadroot ();
  Loadusers (root);
  return users;
}
@Override public
systemconfig getsystemconfig () {
  Element root = Loadroot ();
  Loadsystem (root);
  return system;
}

The Configutil.getdocument (DTD, XML) method is as follows:

 public static Document GetDocument (Final InputStream DTD, InputStream xml) throws Parser ConfigurationException, Saxexception, IOException {documentbuilderfactory factory = Documentbuilderfactory.newi
Nstance ();
    Factory.setvalidating (FALSE);
    Factory.setnamespaceaware (FALSE);
    Documentbuilder builder = Factory.newdocumentbuilder (); Builder.setentityresolver (New Entityresolver () {@Override public inputsource resolveentity (String publicid, S
      Tring SystemID) {return new InputSource (DTD);
    }
    });
      Builder.seterrorhandler (New ErrorHandler () {@Override public void warning (saxparseexception e) {}
      @Override public void error (Saxparseexception e) throws saxexception {throw e;
      @Override public void FatalError (Saxparseexception e) throws saxexception {throw e;
    }
    });
  return Builder.parse (XML); } 

Obviously it's not a good way to handle it. Because the configuration file will be repeated multiple times.

1. First time optimization:

Why not read it once and then cache it? Then other methods use the cache directly when calling Loadroot (). But there is a problem, InputStream can not be cached, and then read repeatedly, because once the InputStream is read, its POS pointers, and so on will change, cannot be read repeatedly. Therefore, only the contents of the configuration file can be read processing, put into byte[] in the cache, and then with Bytearrayoutputstream, you will be able to read the contents of the byte[cache repeatedly. Then use Bytearrayoutputstream to construct InputStream to read the configuration file once, and then repeat the construction inputstream for repeated reads, the relevant code is as follows:

In order to avoid frequent calls to Loadroot in the original code to frequently read/mycat.dtd and/mycat.xml, two files are cached,
//Note that this is not always cached in memory, as Localloader objects are recycled, Cached memory will naturally be reclaimed as well.
private static byte[] Xmlbuffer = null;
private static byte[] Dtdbuffer = null;
private static Bytearrayoutputstream Xmlbaos = null;
private static Bytearrayoutputstream Dtdbaos = null;
static {
  InputStream input = ConfigFactory.class.getResourceAsStream ("/mycat.dtd");
  if (input!= null) {
    Dtdbuffer = new byte[1024 *);
    Dtdbaos = new Bytearrayoutputstream ();
    Bufferfilestream (input, Dtdbuffer, Dtdbaos);
  }
  input = ConfigFactory.class.getResourceAsStream ("/mycat.xml");
  if (input!= null) {
    Xmlbuffer = new byte[1024 *);
    Xmlbaos = new Bytearrayoutputstream ();
    Bufferfilestream (input, Xmlbuffer, Xmlbaos);
  }

Bufferfilestream Method:

private static void Bufferfilestream (InputStream input, byte[] buffer, Bytearrayoutputstream baos) {
  int len = -1;
   
    try {
    while (len = input.read (buffer) >-1) {
      baos.write (buffer, 0, Len);
    }
    Baos.flush ();
  } catch (IOException e) {
    e.printstacktrace ();
    Logger.error ("Bufferfilestream error:" + e.getmessage ());
  }

   

Loadroat optimization is followed by the following:

private static Element Loadroot () {
  element root = null;
  InputStream mycatxml = null;
  InputStream mycatdtd = null;
  if (Xmlbaos!= null)
    mycatxml = new Bytearrayinputstream (Xmlbaos.tobytearray ());
  if (Dtdbaos!= null)
    MYCATDTD = new Bytearrayinputstream (Dtdbaos.tobytearray ());
  try {
  root = configutil.getdocument (Mycatdtd, Mycatxml). Getdocumentelement ();
  parserconfigurationexception | saxexception | IOException E1) {
    e1.printstacktrace ();
    Logger.error ("Loadroot error:" + e1.getmessage ());
  } finally{
    if (mycatxml!= null) {
      try {mycatxml.close ();} catch (IOException e) {}
    }
    if (Mycatdtd!= nu ll) {
      try {mycatdtd.close ();} catch (IOException e) {}} return
  root;

After this optimization, even if there are many ways to call the Loadroot () method frequently, it will not read the configuration file repeatedly, but instead use the byte[] content to duplicate the construction inputstream.

In fact, the principle is to use byte[] as an intermediary container, the byte cache, Bytearrayoutputstream will inputstream read byte stored like byte[] container, and then use Bytearrayinputstream reads the contents from the byte[] container, constructs the InputStream, and as long as byte[the cache container exists, it can repeatedly construct the InputStream. The problem of reading a configuration file is achieved by reading a configuration file, and repeatedly constructing a inputstream to avoid the inputstream of each construction once.

2. Second optimization:

Maybe you'll think of a better way, like:

Why don't we keep the private static Element root = null; As a class property, cached so that there is no need to repeatedly open and close the configuration file, modify the following:

public class Localloader implements Configloader {private static final Logger Logger = Loggerfactory.getlogger ("LocalL
  Oader ");  
  // ... ..
  private static Element root = null;
    The Loadroot method is then changed to: private static Element Loadroot () {InputStream DTD = null;
InputStream XML = null;
    Element root = null;
        if (root = = null) {try {DTD = ConfigFactory.class.getResourceAsStream ("/mycat.dtd");
        XML = ConfigFactory.class.getResourceAsStream ("/mycat.xml");
      Root = Configutil.getdocument (DTD, XML). Getdocumentelement ();
      catch (Configexception e) {throw e;
      catch (Exception e) {throw new Configexception (e);
          Finally {if (DTD!= null) {try {dtd.close ();
          catch (IOException e) {}} if (XML!= null) {try {xml.close ();
  The catch (IOException e) {}}} is return root;  }

This does not require and does not repeatedly open and close the configuration file. As long as the root attribute is not reclaimed, the Document object introduced by Root is also in the cache. This is obviously a lot better than the first optimization, because the first optimization is to repeat the construction of the InputStream from byte[, and then build the Document object again.

3. Third-time optimization

Above is the private static Element root = null; Caching as a property to avoid duplicate reads. So why don't we just cache the Document object as a property? And with better semantics, the code is better understood. The code is as follows:

public class Localloader implements Configloader {private static final Logger Logger = Loggerfactory.getlogger ("LocalL
  Oader "); ...//In order to avoid frequent calls to Loadroot in the original code to frequently read/mycat.dtd and/mycat.xml, the document is cached, private static document document
  = NULL;
    private static Element Loadroot () {InputStream DTD = null;    
    InputStream XML = null;
        if (document = = null) {try {DTD = ConfigFactory.class.getResourceAsStream ("/mycat.dtd");
        XML = ConfigFactory.class.getResourceAsStream ("/mycat.xml");
        Document = Configutil.getdocument (DTD, XML);
      return Document.getdocumentelement ();
        catch (Exception e) {logger.error ("Loadroot error:" + e.getmessage ());
      throw new Configexception (e); Finally {if (DTD!= null) {try {dtd.close ();} catch (IOException e) {}}} if (XML != null) {try {xml.close ();} catch (IOException e) {}}} return DOcument.getdocumentelement ();  }

This is the more qualified implementation. Anyway, the first optimization, learned the Bytearrayoutputstream and Bytearrayinputstream with byte[] in conjunction with the method.

---------------------Split Line------------------------------------

Reference article: http://blog.csdn.net/it_magician/article/details/9240727 the original text is as follows:

Sometimes we need to use the same InputStream object more than once. For example, the client obtains the data from the server, uses the HttpURLConnection getInputStream () method obtains the Stream object, then both displays the data to the foreground (first reads), but also wants the data to write in the file cache to the local (second reads).

But the first time you read the InputStream object, the second time you read it may have gone to the end of the stream (eofexception) or the stream has been close off.

The InputStream object itself cannot be replicated because it does not implement the Cloneable interface. At this point, you can first convert InputStream into Bytearrayoutputstream, after the use of InputStream objects, and then from Bytearrayoutputstream converted back to the good. The code implementation is as follows:

InputStream input = Httpconn.getinputstream ();
Bytearrayoutputstream BAOs = new Bytearrayoutputstream ();
byte[] buffer = new byte[1024];
int Len;
while (len = input.read (buffer)) >-1) {
  baos.write (buffer, 0, Len);
}
Baos.flush ();       
InputStream stream1 = new Bytearrayinputstream (Baos.tobytearray ());
TODO: Show to foreground
inputstream stream2 = new Bytearrayinputstream (Baos.tobytearray ());

Bytearrayinputstream and Bytearrayoutputstream class usage in Java

Bytearrayinputstream and Bytearrayoutputstream, used in IO streaming to read and write byte array content to support functions like memory virtual files or memory-mapped files

Instance:

 import java.io.*; 
    public class Bytearraystreamtest {public static void main (string [] args) {string str = "ABCDEF"; 
    Bytearrayinputstream in = new Bytearrayinputstream (Str.getbytes ()); 
    Bytearrayoutputstream out = new Bytearrayoutputstream (); 
    Transform (in, out); 
    Byte[] result = Out.tobytearray (); 
    System.out.println (out); 
    System.out.println (new String (result)); Transform (system.in, System.out); 
    Read from keyboard, output to monitor} public static void transform (InputStream in, outputstream out) {int ch = 0; 
        try {while (ch = in.read ())!=-1) {int upperchar = character.touppercase ((char) ch); 
      Out.write (Upperchar); }//Close while} catch (Except 
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.