数据输出流允许应用程序以与机器无关方式将Java基本数据类型写到底层输出流。
1.字段:
protected int written
// 到目前为止写入数据输出流的字节数。
2.构造方法:
DataOutputStream(OutputStream out)
//创建一个新的数据输出流,将数据写入指定基础输出流。
3.写方法:
(1)基本数据类型写入方法:八种基本类型:六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
void writeByte(int v)
将一个 byte 值以 1-byte 值形式写出到基础输出流中。
void writeShort(int v)
将一个 short 值以 2-byte 值形式写入基础输出流中,先写入高字节。
void writeInt(int v)
将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。
void writeLong(long v)
将一个 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。
void writeFloat(float v)
使用 Float 类中的 floatToIntBits 方法将 float 参数转换为一个 int 值,
然后将该 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。
void writeDouble(double v)
使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,
然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。
void writeChar(int v)
将一个 char 值以 2-byte 值形式写入基础输出流中,先写入高字节。
void writeBoolean(boolean v)
将一个 boolean 值以 1-byte 值形式写入基础输出流。
(2)字节数组的写入方法
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入基础输出
(3)只写入int的第八位
void write(int b)
将指定字节(参数 b 的八个低位)写入基础输出流。
(4)写入字符串的方法
void writeBytes(String s) 将字符串按字节顺序写出到基础输出流中。
void writeChars(String s) //采用UTF-16be方式写入,也就是java字符串的编码
将字符串按字符顺序写入基础输出流。
void writeUTF(String str)
以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础
4.其他方法
void flush()
//清空此数据输出流。写入文件
int size()
//返回计数器 written 的当前值,即到目前为止写入此数据输出流的字节数。
读写个文件试试:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test
{
public static void main(String[] args) throws IOException
{
FileOutputStream out = new FileOutputStream("testDataOutputStream.txt");
DataOutputStream dos = new DataOutputStream(out);
byte b = 20;
short s = 30;
int a = 900;
float f = 12.3f;
long l = 800l;
double d = 14.23;
boolean flag = true;
char ch = '中';
dos.writeByte(b);// 写入byte类型数据
dos.writeShort(s);// 写入short类型数据
dos.writeInt(a);// 写入int类型
dos.writeFloat(f);// 写入float类型
dos.writeLong(l);// 写入long类型
dos.writeDouble(d);// 写入double类型
dos.writeBoolean(flag);
dos.writeChar(ch);// 写入char类型
dos.close();
out.close();
System.out.println(b);
System.out.println(s);
System.out.println(a);
System.out.println(f);
System.out.println(l);
System.out.println(d);
System.out.println(flag);
System.out.println(ch);
System.out.println("------------------------------");
FileInputStream in = new FileInputStream("testDataOutputStream.txt");
DataInputStream dif = new DataInputStream(in);
byte btemp;
short stemp;
int atemp;
float ftemp;
long ltemp;
double dtemp;
boolean flagtemp;
char chtemp;
btemp = dif.readByte();
stemp = dif.readShort();
atemp = dif.readInt();
ftemp = dif.readFloat();
ltemp = dif.readLong();
dtemp = dif.readDouble();
flagtemp = dif.readBoolean();
chtemp = dif.readChar();
// stringtemp=dif.read
System.out.println(btemp);
System.out.println(stemp);
System.out.println(atemp);
System.out.println(ftemp);
System.out.println(ltemp);
System.out.println(dtemp);
System.out.println(flagtemp);
System.out.println(chtemp);
dif.close();
in.close();
}
}
运行结果:
20
30
900
12.3
800
14.23
true
中
------------------------------
20
30
900
12.3
800
14.23
true
中
DataInputStream的API
1.构造方法
DataInputStream(InputStream in)
使用指定的底层 InputStream 创建一个 DataInputStream。
2.基本类型读取方法:
byte readByte() ;//读取并返回一个输入字节。该字节被看作是 -128 到 127(包含)范围内的一个有符号值。
int readInt() ;//读取四个输入字节并返回一个 int 值。
short readShort() ;//参见 DataInput 的 readShort 方法的常规协定。
long readLong() ;//读取八个输入字节并返回一个 long 值。
float readFloat() ;//读取四个输入字节并返回一个 float 值。
double readDouble() ;//读取八个输入字节并返回一个 double 值。实现这一点的方法是:
先使用与 readlong 方法完全相同的方式构造一个 long 值,
然后使用与 Double.longBitsToDouble 方法完全相同的方式将此 long 值转换成一个 double 值。
boolean readBoolean() ;//读取一个输入字节,如果该字节不是零,则返回 true,如果是零,则返回 false。
char readChar() ;//读取两个输入字节并返回一个 char 值。
3.字符串读取方法
String readUTF();//读入一个已使用 UTF-8 修改版格式编码的字符串。
static String readUTF(DataInput in)
从流 in 中读取用 UTF-8 修改版格式编码的 Unicode 字符格式的字符串;然后以 String 形式返回此字符串。
可以看到DataInputStream中读取字符串只有readUTF()方法,没有与DataOutputStream对应的:
void writeBytes(String s) 将字符串按字节顺序写出到基础输出流中。
void writeChars(String s) //采用UTF-16be方式写入,也就是java字符串的编码
将字符串按字符顺序写入基础输出流。
这两个方法,使用DataOutputStream的这两个方法写入字符串时,DataInputStream来读取可能比较麻烦。
4.无符号整数读取方法,DataInputStream中并没有写入无符号整数的方法,这两个方法是不是用不到?
(4)无符号整数读取方法
int readUnsignedByte();// 读取一个输入字节,将它左侧补零 (zero-extend) 转变为 int 类型,并返回结果,所以结果的范围是 0 到 255。
如果接口 DataOutput 的 writeByte 方法的参数是 0 到 255 之间的值,则此方法适用于读取用 writeByte 写入的字节。
int readUnsignedShort();// 读取两个输入字节,并返回 0 到 65535 范围内的一个 int 值。
如果接口 DataOutput 的 writeShort 方法的参数是 0 到 65535 范围内的值,
则此方法适用于读取用 writeShort 写入的字节。
5.读取字节数组的方法:
int read(byte[] b)
从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。
int read(byte[] b, int off, int len)
从包含的输入流中将最多 len 个字节读入一个 byte 数组中。
void readFully(byte[] b);//从输入流中读取一些字节,并将它们存储在缓冲区数组 b 中。读取的字节数等于 b 的长度。
void readFully(byte[] b, int off, int len);//从输入流中读取 len 个字节到字节数组b,从b的off下标开始读入。
6.同样是读取字节数组的方法,read(byte[] b)和readFully(byte[] b)的区别:
参考两篇前辈的博文:
前辈1:
DataInputStream类中的read(byte[] b)和readFully(byte[] b)读取消息到底有什么区别呢?
(1) 其实read(byte[] b)方法和readFully(byte []b)都是利用InputStream中read()方法,每次读取的也是一个字节,只是读取字节数组的方式不同.
(2) read(byte[] b)方法实质是读取流上的字节直到流上没有字节为止,如果当声明的字节数组长度大于流上的数据长度时就提前返回,而readFully(byte[] b)方法是读取流上指定长度的字节数组,也就是说如果声明了长度为len的字节数组,readFully(byte[] b)方法只有读取len长度个字节的时候才返回,否则阻塞等待,如果超时,则会抛出异常 EOFException。
(3) 那么当发送了长度为len的字节,那么为什么用read方法用户收不全呢,揪其原因我们发现消息在网络中传输是没那么理想的,我们发的那部分字节数组在传送过程中可能在接受信息方的缓存当中或者在传输线路,极端情况下可能在发送方的缓存当中,这样就不在流上,所以read方法提前返回了,这样就造成了各种错误。
出处:输入流当中的read方法和readfully方法的区别与原理
前辈2:
readFully()源码:
public void readFully(byte[] b, int off, int len, boolean copy)
throws IOException
{
while (len > 0) {
int n = read(b, off, len, copy);
if (n < 0) {
throw new EOFException();
}
off += n;
len -= n;
}
}
从这里不难看出!这里对异常并没有处理!而是直接抛出异常!
这里还要注意的一个问题就是其实 readFully和read的区别。
readFully方法并不是说一下就把整个文件读完了,不用去管是否到达文件末尾的异常。
readFully只是在读取数据的时候,会一直把缓冲区读满,否则一直处于阻塞状态而等待读取。
而read方法只是将字节流中的数据读完。那么数据在TCP协议传送的过程中,可能输入流接受到的数据并不完全,只是其中的一部分。而如果这时候的缓冲区没有满的话,readFully将会继续等待。知道缓冲区装满。
某些时候!你可能需要读出特定的长度的字段。比如一些数据的头信息之类的!
这时候如果你用read去读,那么可能还没有读完就个你返回来了。
但是如果去用readFully读,那么就会完整的给你读出来。
但是在更多的时候,如果不是确定要用特定长度的数据。还是用read去读。
用readFully有点危险。
总结:懒得总结,以后再总结。
7.跳过n个字节:
int skipBytes(int n)
试图在输入流中跳过数据的 n 个字节,并丢弃跳过的字节。