ZetCode

Java DataInputStream 类

最后修改时间:2025 年 4 月 16 日

java.io.DataInputStream 类允许从底层输入流中读取 Java 原始数据类型。它以一种与机器无关的方式读取数据。这对于读取由 DataOutputStream 写入的数据非常有用。

DataInputStream 实现了 DataInput 接口。它封装了另一个 InputStream 并提供了读取原始数据类型的方法。在没有外部同步的情况下,该类不是线程安全的,不适合并发访问。

DataInputStream 类概述

DataInputStream 继承了 FilterInputStream 并提供了读取 Java 原始数据类型的方法。 关键方法包括读取各种数据类型,如 int、double、boolean 等。所有方法都以大端格式读取数据。

public class DataInputStream extends FilterInputStream implements DataInput {
    public DataInputStream(InputStream in);
    public final int read(byte[] b) throws IOException;
    public final int read(byte[] b, int off, int len) throws IOException;
    public final boolean readBoolean() throws IOException;
    public final byte readByte() throws IOException;
    public final char readChar() throws IOException;
    public final double readDouble() throws IOException;
    public final float readFloat() throws IOException;
    public final int readInt() throws IOException;
    public final long readLong() throws IOException;
    public final short readShort() throws IOException;
    public final String readUTF() throws IOException;
    public final int readUnsignedByte() throws IOException;
    public final int readUnsignedShort() throws IOException;
    public final int skipBytes(int n) throws IOException;
}

上面的代码显示了 DataInputStream 提供的关键方法。 这些方法允许从流中读取原始数据类型。如果意外到达流的末尾,读取方法会抛出 EOFException

创建 DataInputStream

DataInputStream 是通过将其封装在另一个 InputStream 中创建的。通常与文件或网络流一起使用。构造函数将底层流作为参数。完成后始终关闭流。

Main.java
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try {
            // Create with FileInputStream
            FileInputStream fileStream = new FileInputStream("data.bin");
            DataInputStream dataStream = new DataInputStream(fileStream);
            
            System.out.println("DataInputStream created successfully");
            
            dataStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示如何从 FileInputStream 创建 DataInputStream。使用后应正确关闭流。try-with-resources 语句也可用于自动资源管理。

读取原始数据类型

DataInputStream 提供了读取所有 Java 原始类型的方法。 每种方法读取该类型所需的字节数。 如果到达流的末尾,这些方法会抛出 EOFException

Main.java
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (DataInputStream dis = 
                new DataInputStream(new FileInputStream("primitives.dat"))) {
            
            boolean boolVal = dis.readBoolean();
            byte byteVal = dis.readByte();
            char charVal = dis.readChar();
            double doubleVal = dis.readDouble();
            float floatVal = dis.readFloat();
            int intVal = dis.readInt();
            long longVal = dis.readLong();
            short shortVal = dis.readShort();
            
            System.out.println("Boolean: " + boolVal);
            System.out.println("Byte: " + byteVal);
            System.out.println("Char: " + charVal);
            System.out.println("Double: " + doubleVal);
            System.out.println("Float: " + floatVal);
            System.out.println("Int: " + intVal);
            System.out.println("Long: " + longVal);
            System.out.println("Short: " + shortVal);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例从文件中读取各种原始类型。 数据必须使用 DataOutputStream 以相同的顺序写入。 读取方法期望数据采用大端格式。每种方法都精确读取该类型所需的字节数。

读取 UTF 字符串

readUTF 方法读取以修改后的 UTF-8 格式编码的字符串。 这与 DataOutputStream.writeUTF 使用的格式相同。 前两个字节表示字符串长度,后跟字符串数据。

Main.java
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (DataInputStream dis = 
                new DataInputStream(new FileInputStream("strings.dat"))) {
            
            String str1 = dis.readUTF();
            String str2 = dis.readUTF();
            
            System.out.println("First string: " + str1);
            System.out.println("Second string: " + str2);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示如何从文件读取 UTF-8 编码的字符串。 这些字符串必须已使用 DataOutputStream.writeUTF 写入。 该方法首先读取长度,然后读取字符串字节。修改后的 UTF-8 处理空字符的方式与标准 UTF-8 不同。

读取字节数组

DataInputStream 提供了读取字节数组的方法。 readFully 方法读取直到缓冲区已满或到达流的末尾。 这些对于读取固定大小的二进制数据非常有用。

Main.java
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (DataInputStream dis = 
                new DataInputStream(new FileInputStream("bytes.dat"))) {
            
            byte[] buffer = new byte[100];
            
            // Read exactly 100 bytes
            dis.readFully(buffer);
            
            System.out.println("Read " + buffer.length + " bytes");
            
            // Read into part of array
            byte[] partialBuffer = new byte[200];
            dis.readFully(partialBuffer, 50, 100);
            
            System.out.println("Read 100 bytes into offset 50");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了如何使用 readFully 读取字节数组。 第一次调用读取一个完整的 100 字节数组。 第二次调用将 100 个字节读取到从偏移量 50 开始的 200 字节数组中。 如果在填充缓冲区之前到达流的末尾,这些方法会抛出 EOFException

跳过字节

skipBytes 方法尝试跳过指定数量的字节。 它返回跳过的实际字节数。 如果到达流的末尾,则可能小于请求的字节数。

Main.java
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (DataInputStream dis = 
                new DataInputStream(new FileInputStream("data.bin"))) {
            
            System.out.println("Available bytes: " + dis.available());
            
            int skipped = dis.skipBytes(50);
            System.out.println("Skipped " + skipped + " bytes");
            
            // Read after skipping
            int value = dis.readInt();
            System.out.println("Read int after skipping: " + value);
            
            // Try to skip beyond end
            skipped = dis.skipBytes(1000);
            System.out.println("Skipped " + skipped + " bytes (end near)");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示如何在流中跳过字节。 第一次跳过向前移动 50 个字节。 第二次尝试跳过 1000 个字节,但如果在接近末尾时可能会跳过较少的字节。 available 方法显示剩余字节数,但对于所有流类型并非总是准确的。

读取无符号值

DataInputStream 提供了读取无符号字节和短整型值的方法。 这些返回的值采用更大的类型 (int) 以适应无符号范围。 在使用使用无符号值的二进制格式时很有用。

Main.java
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {

    public static void main(String[] args) {
        try (DataInputStream dis = 
                new DataInputStream(new FileInputStream("unsigned.dat"))) {
            
            int unsignedByte = dis.readUnsignedByte();
            int unsignedShort = dis.readUnsignedShort();
            
            System.out.println("Unsigned byte: " + unsignedByte);
            System.out.println("Unsigned short: " + unsignedShort);
            
            // Regular read for comparison
            byte signedByte = dis.readByte();
            short signedShort = dis.readShort();
            
            System.out.println("Signed byte: " + signedByte);
            System.out.println("Signed short: " + signedShort);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了如何读取无符号值。 无符号字节方法在 int 中返回 0-255。 无符号 short 返回 0-65535。 与可能返回负值的有符号读取进行比较。 在处理使用无符号值的二进制格式时很有用。

来源

Java DataInputStream 类文档

在本文中,我们介绍了 Java DataInputStream 类的基本方法和特性。 了解这些概念对于在 Java I/O 操作中使用二进制数据和原始类型至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的专业程序员。 我于 2007 年开始撰写编程文章,至今已撰写了 1400 多篇文章和 8 本电子书。 凭借超过 8 年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程