程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java應用ByteArrayOutputStream 和 ByteArrayInputStream 防止反復讀取設置裝備擺設文件的辦法

Java應用ByteArrayOutputStream 和 ByteArrayInputStream 防止反復讀取設置裝備擺設文件的辦法

編輯:關於JAVA

Java應用ByteArrayOutputStream 和 ByteArrayInputStream 防止反復讀取設置裝備擺設文件的辦法。本站提示廣大學習愛好者:(Java應用ByteArrayOutputStream 和 ByteArrayInputStream 防止反復讀取設置裝備擺設文件的辦法)文章只能為提供參考,不一定能成為您想要的結果。以下是Java應用ByteArrayOutputStream 和 ByteArrayInputStream 防止反復讀取設置裝備擺設文件的辦法正文


ByteArrayOutputStream類是在創立它的實例時,法式外部創立一個byte型別數組的緩沖區,然後應用ByteArrayOutputStream和ByteArrayInputStream的實例向數組中寫入或讀出byte型數據。在收集傳輸中我們常常要傳輸許多變量,我們可以應用ByteArrayOutputStream把一切的變量搜集到一路,然後一次性把數據發送出去。詳細用法以下:

ByteArrayOutputStream:    可以捕捉內存緩沖區的數據,轉換成字節數組。

ByteArrayInputStream: 可以將字節數組轉化為輸出流

ByteArrayInputStream類有兩個默許的結構函數:

ByteArrayInputStream(byte[] b): 應用一個字節數組傍邊一切的數據做為數據源,法式可以像輸出流方法一樣讀取字節,可以看作一個虛擬的文件,用文件的方法去讀取它外面的數據。

ByteArrayInputStream(byte[] b,int offset,int length): 從數組傍邊的第offset開端,一向掏出length個這個字節做為數據源。

ByteArrayOutputStream類也有兩個默許的結構函數:

ByteArrayOutputStream(): 創立一個32個字節的緩沖區
ByteArrayOutputStream(int): 依據參數指定年夜小創立緩沖區

比來介入了github上的一個開源項目 Mycat,是一個mysql的分庫分表的中央件。發明個中讀取設置裝備擺設文件的代碼,存在頻仍屢次反復翻開,讀取,封閉的成績,代碼寫的很低級,略微看過一些框架源碼的人,是不會犯如許的毛病的。因而對其停止了一些優化。

優化之前的代碼以下所示:

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 {
    if (dtd != null) {
      try {
        dtd.close();
      } catch (IOException e) { }
    }
    if (xml != null) {
      try {
        xml.close();
      } catch (IOException e) { }
    }
  }
  return root;
} 

然後其它辦法頻仍挪用 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;
}
// ... ... 

ConfigUtil.getDocument(dtd, xml) 辦法以下:

public static Document getDocument(final InputStream dtd, InputStream xml) throws ParserConfigurationException,
      SAXException, IOException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//factory.setValidating(false);
    factory.setNamespaceAware(false);
    DocumentBuilder builder = factory.newDocumentBuilder();
    builder.setEntityResolver(new EntityResolver() {
      @Override
      public InputSource resolveEntity(String publicId, String 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);
  } 

明顯這不是很好的處置方法。由於會屢次反復設置裝備擺設文件。

1. 第一次優化:

為何不讀取一次,然後緩存起來呢?然後其它辦法在挪用 loadRoot() 時,就直接應用緩存中的就好了。然則碰到一個成績,InputStream 是不克不及被緩存,然後反復讀取的,由於 InputStream 一旦被讀取以後,其 pos 指針,等等都邑產生變更,沒法停止反復讀取。所以只能將設置裝備擺設文件的內容讀取處置,放入  byte[] 中緩存起來,然後合營 ByteArrayOutputStream,便可以反復讀取 byte[] 緩存中的內容了。然後應用 ByteArrayOutputStream 來結構 InputStream 就到達了讀取設置裝備擺設文件一次,然後反復結構 InputStream 停止反復讀取,相干代碼以下:

// 為了不原代碼中頻仍挪用 loadRoot 去頻仍讀取 /mycat.dtd 和 /mycat.xml,所以將兩個文件停止緩存,
// 留意這裡其實不會一向緩存在內存中,跟著 LocalLoader 對象的收受接管,緩存占用的內存天然也會被收受接管。
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 * 512];
    dtdBaos = new ByteArrayOutputStream();
    bufferFileStream(input, dtdBuffer, dtdBaos);
  }
  input = ConfigFactory.class.getResourceAsStream("/mycat.xml");
  if(input != null){
    xmlBuffer = new byte[1024 * 512];
    xmlBaos = new ByteArrayOutputStream();
    bufferFileStream(input, xmlBuffer, xmlBaos);
  }
} 

bufferFileStream 辦法:

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 優化以後以下:

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();
  } catch (ParserConfigurationException | SAXException | IOException e1) {
    e1.printStackTrace();
    logger.error("loadRoot error: " + e1.getMessage());
  }finally{
    if(mycatXml != null){
      try { mycatXml.close(); } catch (IOException e) {}
    }
    if(mycatDtd != null){
      try { mycatDtd.close(); } catch (IOException e) {}
    }
  }
  return root;
} 

如許優化以後,即便有許多辦法頻仍挪用 loadRoot() 辦法,也不會反復讀取設置裝備擺設文件了,而是應用 byte[] 內容,反復結構 InputStream 罷了。

其實其道理,就是應用 byte[] 作為一個中央容器,對byte停止緩存,ByteArrayOutputStream 將 InputStream 讀取的 byte 寄存如 byte[]容器,然後應用 ByteArrayInputStream 從 byte[]容器中讀取內容,結構 InputStream,只需 byte[] 這個緩存容器存在,便可以屢次反復結構出 InputStream。 因而到達了讀取一次設置裝備擺設文件,而反復結構出InputStream,防止了每結構一次InputStream,就讀取一次設置裝備擺設文件的成績。

2. 第二次優化:

能夠你會想到更好的辦法,好比:

為何我們不將 private static Element root = null; 作為類屬性,緩存起來,如許就不須要反復翻開和封閉設置裝備擺設文件了,修正以下:

public class LocalLoader implements ConfigLoader {
  private static final Logger logger = LoggerFactory.getLogger("LocalLoader");
  // ... ..  
  private static Element root = null;
  // 然後 loadRoot 辦法改成:
  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();
          } catch (IOException e) { }
        }
      }
    }
    return root;
  } 

如許就不須要也不會反復 翻開和封閉設置裝備擺設文件了。只需 root 屬性沒有被收受接管,那末 root 引入的 Document 對象也會在緩存中。如許明顯比第一次優化要好許多,由於第一次優化,照樣要從 byte[] 反復結構 InputStream, 然後反復 build 出 Document 對象。

3. 第三次優化

下面是將 private static Element root = null; 作為一個屬性停止緩存,防止反復讀取。那末我們干嗎不直接將 Document 對象作為一個屬性,停止緩存呢。並且具有更好的語義,代碼更好懂得。代碼以下:

public class LocalLoader implements ConfigLoader {
  private static final Logger logger = LoggerFactory.getLogger("LocalLoader");
  // ... ...
  // 為了不原代碼中頻仍挪用 loadRoot 去頻仍讀取 /mycat.dtd 和 /mycat.xml,所以將 Document 停止緩存,
  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();
  } 

如許才是比擬及格的完成。anyway, 第一種優化,進修到了 ByteArrayOutputStream 和 ByteArrayInputStream 同 byte[] 合營應用的辦法。

---------------------朋分線------------------------------------

參考文章:http://blog.csdn.net/it_magician/article/details/9240727 原文以下:

有時刻我們須要對統一個InputStream對象應用屢次。好比,客戶端從辦事器獲得數據 ,應用HttpURLConnection的getInputStream()辦法取得Stream對象,這時候既要把數據顯示到前台(第一次讀取),又想把數據寫進文件緩存到當地(第二次讀取)。

但第一次讀取InputStream對象後,第二次再讀取時能夠曾經到Stream的開頭了(EOFException)或許Stream曾經close失落了。

而InputStream對象自己不克不及復制,由於它沒有完成Cloneable接口。此時,可以先把InputStream轉化成ByteArrayOutputStream,前面要應用InputStream對象時,再從ByteArrayOutputStream轉化回來就行了。代碼完成以下:

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:顯示到前台
InputStream stream2 = new ByteArrayInputStream(baos.toByteArray());
//TODO:當地緩存 

java中ByteArrayInputStream和ByteArrayOutputStream類用法

ByteArrayInputStream和ByteArrayOutputStream,用於以IO流的方法來完成對字節數組內容的讀寫,來支撐相似內存虛擬文件或許內存映照文件的功效

實例:

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); // 從鍵盤讀,輸入到顯示器 
  } 
  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
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved