Java 中的 DataInputStream 类(位于java.io包下),能够让开发者从 InputStream 中读取 Java 基本数据类型(如int、float、long等),而不只是读取原始字节。具体操作时,将 InputStream 封装在 DataInputStream 内,之后便可借助 DataInputStream 来读取 Java 基本数据类型。它之所以被称作DataInputStream,正是因为其读取的是数据(数值),而非单纯的字节 。
当你需要读取的数据包含大于单字节的 Java 基本数据类型(像 int、long、float、double 等)时,DataInputStream 会是个极为实用的工具。DataInputStream 要求多字节的基本数据类型按照网络字节顺序(大端字节序,即最重要的字节排在最前面)进行写入。注意:
(1)通常你会使用 DataInputStream 来读取 DataOutputStream 写入的数据。
(2)DataInputStream 类是 InputStream 的子类。这意味着 DataInputStream 同样具备基础的读取功能,它能够从底层的 InputStream 中读取单个字节,或者将数据读取到字节数组里,以满足一些特定场景的需求。
(3)在读取原始数据类型时,我们无法区分有效的 int 值 -1 和正常的流结束标记。这实际上表明,从返回的原始数据值里,我们无法判断是否已经抵达流的末尾。所以,你必须预先知晓要读取的数据类型及其顺序。简单来说,你得提前清楚能从 DataInputStream 中读取哪些数据。
下面是一个 DataInputStream 示例:
package com.hxstrive.java_io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.nio.ByteBuffer; public class DataInputStreamExample { public static void main(String[] args) throws Exception { // 准备数据,一个字节数组 ByteArrayOutputStream output = new ByteArrayOutputStream(); // 写入一个字节 output.write(10); // 一个 int output.write(ByteBuffer.allocate(4).putInt(128).array()); // 一个 float output.write(ByteBuffer.allocate(4).putFloat(58.34f).array()); // 一个 double output.write(ByteBuffer.allocate(8).putDouble(5089.04f).array()); // 尝试从 DataInputStream 读取数据 try (DataInputStream input = new DataInputStream(new ByteArrayInputStream(output.toByteArray()))) { int aByte = input.read(); System.out.println("aByte=" + aByte); int anInt = input.readInt(); System.out.println("anInt=" + anInt); float aFloat = input.readFloat(); System.out.println("aFloat=" + aFloat); double aDouble = input.readDouble(); System.out.println("aDouble=" + aDouble); } catch (Exception e) { e.printStackTrace(); } } }
运行输出:
aByte=10 anInt=128 aFloat=58.34 aDouble=5089.0400390625
上面示例,创建了一个 ByteArrayOutputStream 类,利用 ByteBuffer 类向 OutputStream 中分别写入 byte、int、float 和 double 类型的样例数据,使用 output.toByteArray() 方法获取样例数据的字节数组去创建 DataInputStream。最后,从 DataInputStream 中读取刚刚写入的 byte、int、float 和 double 样例数据。
你可以利用构造函数来创建 Java 的 DataInputStream 对象。在创建过程中,你需要传入一个 InputStream 作为参数,DataInputStream 会从这个 InputStream 里读取原始数据类型的数据。
示例:
DataInputStream dataInputStream = new DataInputStream(new FileInputStream("data.bin"));
如前所述,DataInputStream 类经常与 DataOutputStream 类一起使用。下面举例说明先用 DataOutputStream 写入数据,然后再用 DataInputStream 读取数据。示例:
package com.hxstrive.java_io; import java.io.*; public class DataInputStreamExample2 { public static void main(String[] args) throws IOException { // 临时存放数据 ByteArrayOutputStream output = new ByteArrayOutputStream(); // 写入数据到 DataOutputStream try (DataOutputStream dataOutputStream = new DataOutputStream(output)) { dataOutputStream.writeInt(123); dataOutputStream.writeFloat(123.45F); dataOutputStream.writeLong(789); } // 使用 DataInputStream 读取 DataOutputStream 写出的数据 try(DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(output.toByteArray()))) { int int123 = dataInputStream.readInt(); float float12345 = dataInputStream.readFloat(); long long789 = dataInputStream.readLong(); System.out.println("int123 = " + int123); System.out.println("float12345 = " + float12345); System.out.println("long789 = " + long789); } } }
运行输出:
int123 = 123 float12345 = 123.45 long789 = 789
上述示例,首先创建 DataOutputStream 类,然后将 int、float 和 long 值写入 ByteArrayOutputStream,临时存放(当然,你也可以直接写入到某个文件)。其次,示例创建了一个 DataInputStream,从 ByteArrayOutputStream 返回的字节数组中读入 int、float 和 long 值。
readBoolean() 方法从 DataInputStream 中读取布尔值。
readByte() 方法从 DataInputStream 中读取字节。
readUnsignedByte() 方法从 DataInputStream 读取 Java 无符号字节(只有正值)。无符号字节会以 int 的形式返回,因为超过 127 的字节值无法放入有符号字节数据类型中。
readChar() 方法从 DataInputStream 中读取字符。
readDouble() 方法从 DataInputStream 中读取double。
readFloat() 方法从 DataInputStream 中读取 float。
readShort() 方法从 DataInputStream 中读取 short。
readUnsignedShort() 方法从 DataInputStream 读取 Java 无符号 short(只有正值)。无符号短字符将作为 int 返回,因为超过 32767 的短字符值无法放入有符号短字符数据类型中。
readInt() 方法从 DataInputStream 中读取一个 int。
readLong() 方法从 DataInputStream 中读取 long。
readUTF() 方法从 DataInputStream 中读取字符串。注意,要使用该方法读取数据,数据必须以 UTF-8 编码。
当你完成从 DataInputStream 中读取数据的操作后,务必记得将其关闭。需要注意的是,关闭 DataInputStream 时,与之关联的用于读取数据的 InputStream 实例也会随之关闭。
若要关闭 DataInputStream,只需调用其 close() 方法即可。下面为你展示关闭 DataInputStream 的具体操作流程:
dataInputStream.close();
你还可以使用 Java 7 中引入的 try-with-resources 结构。例如:
InputStream input = new FileInputStream("data.bin"); try(DataInputStream dataInputStream = new DataInputStream(input)){ int data = dataInputStream.readInt(); //.... }
需留意的是,此处已不存在任何显式的 close() 方法调用。这是因为 try-with-resources 结构已自动处理了资源关闭的问题。
同时还要注意,第一个 FileInputStream 实例并非在 try-with-resources 代码块中创建。这表明 try-with-resources 块不会自动关闭该 FileInputStream 实例。然而,由于关闭 DataInputStream 时,它会同时关闭其用于读取数据的 InputStream 实例,所以 FileInputStream 实例会在 DataInputStream 关闭时一同被关闭 。