1. 程式人生 > >Guava ByteSreams 常用方法的封裝,FileInputStream的兄弟ByteArrayInputSteam,裝飾類大兄弟DataOutputStream

Guava ByteSreams 常用方法的封裝,FileInputStream的兄弟ByteArrayInputSteam,裝飾類大兄弟DataOutputStream

ByteArrayInputSteam

JDK解釋:一個從位元組陣列讀取的輸入流包含一個內部緩衝區包含的位元組,可以從流中讀取。內部計數器跟蹤由讀方法提供的下一個位元組。Closing a ByteArrayInputStream has no effect. The methods in this class can be called after the stream has been closed without generating an IOException.

ByteArrayInputStream(byte[] buf) 引數buf指定位元組陣列型別的資料來源。 ByteArrayInputStream(byte[] buf, int offset, int lenght) 引數buf指定位元組陣列型別資料來源,引數offset指定從陣列中開始讀取資料的起始下標位置,lenght指定從陣列中讀取的位元組數。
ByteArrayInputStream類本身採用了介面卡設計模式,它把位元組陣列型別轉換為輸入流型別,使得程式能夠對位元組陣列進行讀操作。這個和FileInputStream差不多,將File轉換為位元組流。

原始碼:這裡的mark 和 pos和NIO中的有點類似哦!將資料從byte[]轉換為Inputstream的包裝類?哈哈沒有使用過誒,看Guava的原始碼中才看到這個的使用。

 public class ByteArrayInputStream extends InputStream {

    protected byte buf[];

    protected int pos;

    protected int mark = 0;

    protected int count;

    public ByteArrayInputStream(byte buf[]) {
        this
.buf = buf; this.pos = 0; this.count = buf.length; } public ByteArrayInputStream(byte buf[], int offset, int length) { this.buf = buf; this.pos = offset; this.count = Math.min(offset + length, buf.length); this.mark = offset; } public synchronized
int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1; } public synchronized int read(byte b[], int off, int len) { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } if (pos >= count) { return -1; } int avail = count - pos; if (len > avail) { len = avail; } if (len <= 0) { return 0; } System.arraycopy(buf, pos, b, off, len); pos += len; return len; } public synchronized long skip(long n) { long k = count - pos; if (n < k) { k = n < 0 ? 0 : n; } pos += k; return k; } /** * Returns the number of remaining bytes that can be read *(or skipped over) * from this input stream. */ public synchronized int available() { return count - pos; } public void mark(int readAheadLimit) { mark = pos; } public synchronized void reset() { pos = mark; } /** * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in * this class can be called after the stream has been closed without * generating an <tt>IOException</tt>. */ public void close() throws IOException { } }

DataOutputStream繼承FilterOutputStream(包裝類都繼承這個)

FilterOutputStream裝飾類的核心

 public class FilterOutputStream extends OutputStream {

    protected OutputStream out;
    public FilterOutputStream(OutputStream out) {
        this.out = out;
    }  
    public void write(int b) throws IOException {
        out.write(b);
    }
}

是Java中輸入輸出流的裝飾類
A data output stream lets an application write primitive Java data(原生的Java資料資訊到位元組流中,提供了一種便利的方式) types to an output stream in a portable way. An application can then use a data input stream to read the data back in.
什麼是原生的資料資訊呢?int,short,long,double,string等等,因為輸入到流中是使用位元組為單元的,比如int是4個位元組,要使用包裝類才方便得到位元組陣列,那麼原生的資料資訊就需要自己一個個位元組的寫入啦,非常的不方便,所以這個的意義也是在於處理這些資料資訊哦!

  • writeInt:Writes an int to the underlying output stream as four bytes, high byte first. 這個的處理可以看懂吧,就是簡單的處理int的四個位元組。

    public final void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);
    }
  • WriteUTF更加的好玩一些,因為UTF-8的編碼方式,有的使用一個位元組,有的使用二個位元組,有的使用三個位元組,所有在DataOutputStream處理中首先是處理String的長度轉換為UTF-8需要多少位元組,然後在前兩位寫入資料的長度,後面才開始處理資料資訊。這些DataInputStrem都幫我們進行了處理所以使用起來非常的方便。
  • WriteUTF 計算長度
        for (int i = 0; i < strlen; i++) {
            c = str.charAt(i);
            if ((c >= 0x0001) && (c <= 0x007F)) { //1-127
                utflen++;
            } else if (c > 0x07FF) {
                utflen += 3;
            } else {
                utflen += 2;
            }
        }
     // Data Stream寫到輸入流中
    DataOutputStream dos = new DataOutputStream(new FileOutputStream(
            "datasteam.txt"));

    //按2位元組寫入,都是寫入的低位
    dos.writeBytes("世界"); 

    // 按照Unicode寫入 JDK預設的方式
    dos.writeChars("世界"); 

    // 按照UTF-8寫入UTF8變長
    //開頭2位元組是由writeUTF函式寫入的長度資訊,
    方便readUTF函式讀取)
    dos.writeUTF("世界"); 
    dos.flush();
    dos.close();
 ```

 *  writeBytes這裡進行了強制轉換,肯定會丟失精度的。
 ```
 public final void writeBytes(String s) throws IOException {
        int len = s.length();
        for (int i = 0 ; i < len ; i++) {
            out.write((byte)s.charAt(i));
        }
        incCount(len);
    }
  • writeChars這個就好理解的,兩個位元組處理。
public final void writeChars(String s) throws IOException {
        int len = s.length();
        for (int i = 0 ; i < len ; i++) {
            int v = s.charAt(i);
            out.write((v >>> 8) & 0xFF);
            out.write((v >>> 0) & 0xFF);
        }
        incCount(len * 2);
    }

Guava ByteStreams 處理位元組流資訊

提供了一些非常有用的方法,感覺還不錯,比如複製位元組流到一個另外的一個輸出流,將inputStream轉換為byte資料
* copy:

public static long copy(InputStream from, OutputStream to) throws IOException {
    checkNotNull(from);
    checkNotNull(to);
    byte[] buf = new byte[8192];
    long total = 0;
    while (true) {
      int r = from.read(buf);
      if (r == -1) {
        break;
      }
      to.write(buf, 0, r);
      total += r;
    }
    return total;
  }
  • 轉換為byte陣列:是不是很方便!其他的方法不想使用了就這兩個非常的可以的!
public static byte[] toByteArray(InputStream in) throws IOException {
    // Presize the ByteArrayOutputStream since we know how large it will need
    // to be, unless that value is less than the default ByteArrayOutputStream
    // size (32).
    ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(32, in.available()));
    copy(in, out);
    return out.toByteArray();
}

總結

對於流資訊的認識更加深了一份理解.