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;
}
}
- http://www.tuicool.com/articles/RnQvEn 使用DataOutputStream
// 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();
}
还有个charStream也是和ByteStream差不多
* http://ajoo.iteye.com/blog/737718
总结
对于流信息的认识更加深了一份理解.