ZetCode

Java DataInput 接口

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

java.io.DataInput 接口提供了从输入流读取二进制数据的方法。 它定义了以与机器无关的方式读取基本类型和字符串的操作。 实现此接口的类可以读取由 DataOutput 实现写入的数据。

DataInputDataInputStreamRandomAccessFile 等类实现。 该接口确保了数据读取的一致性,而与底层平台无关。 默认情况下,所有方法都以大端格式读取数据。

DataInput 接口概述

DataInput 接口包含读取基本类型和字符串的方法。 它包括读取字节、布尔值、字符和其他数据类型的方法。 该接口还提供了读取 UTF-8 编码字符串的方法。

public interface DataInput {
    void readFully(byte[] b) throws IOException;
    void readFully(byte[] b, int off, int len) throws IOException;
    int skipBytes(int n) throws IOException;
    boolean readBoolean() throws IOException;
    byte readByte() throws IOException;
    int readUnsignedByte() throws IOException;
    short readShort() throws IOException;
    int readUnsignedShort() throws IOException;
    char readChar() throws IOException;
    int readInt() throws IOException;
    long readLong() throws IOException;
    float readFloat() throws IOException;
    double readDouble() throws IOException;
    String readLine() throws IOException;
    String readUTF() throws IOException;
}

上面的代码显示了完整的 DataInput 接口。 每个方法都从输入流中读取特定的数据类型。 该接口会为任何 I/O 错误抛出 IOException。 如果到达流的末尾,某些方法可能会抛出 EOFException

使用 DataInputStream 读取基本类型

DataInputStreamDataInput 最常见的实现。 它封装了一个 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 (DataInputStream dis = 
                new DataInputStream(new FileInputStream("data.bin"))) {
            
            // Read different data types
            boolean boolVal = dis.readBoolean();
            byte byteVal = dis.readByte();
            char charVal = dis.readChar();
            short shortVal = dis.readShort();
            int intVal = dis.readInt();
            long longVal = dis.readLong();
            float floatVal = dis.readFloat();
            double doubleVal = dis.readDouble();
            
            System.out.println("Boolean: " + boolVal);
            System.out.println("Byte: " + byteVal);
            System.out.println("Char: " + charVal);
            System.out.println("Short: " + shortVal);
            System.out.println("Int: " + intVal);
            System.out.println("Long: " + longVal);
            System.out.println("Float: " + floatVal);
            System.out.println("Double: " + doubleVal);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了从二进制文件读取基本类型。 数据必须以写入时的相同顺序读取。 DataInputStream 会自动将字节转换为适当的基本类型。 try-with-resources 语句确保正确关闭流。

使用 readFully 读取字节数组

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("binary.dat"))) {
            
            // Read fixed-size header
            byte[] header = new byte[16];
            dis.readFully(header);
            System.out.println("Header read: " + new String(header));
            
            // Read data with offset
            byte[] data = new byte[1024];
            dis.readFully(data, 0, 512); // Read first half
            dis.readFully(data, 512, 512); // Read second half
            
            System.out.println("Data read successfully");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了 readFully 的两个变体。 第一个读取完整的字节数组,而第二个读取数组的一部分。 如果在读取所有字节之前到达流的末尾,这两个方法都会抛出 EOFException。 它们对于读取固定大小的数据结构非常有用。

读取 UTF-8 字符串

readUTF 方法读取以修改后的 UTF-8 格式编码的字符串。 此格式以一个两字节的长度开头,后跟字符串字节。 它通常用于序列化和网络通信。

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"))) {
            
            // Read UTF string
            String str1 = dis.readUTF();
            System.out.println("First string: " + str1);
            
            // Read another UTF string
            String str2 = dis.readUTF();
            System.out.println("Second string: " + str2);
            
            // Read remaining strings
            while (dis.available() > 0) {
                System.out.println("Next string: " + dis.readUTF());
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了从二进制文件读取 UTF-8 编码的字符串。 readUTF 方法首先读取长度,然后读取字符串字节。 available 方法检查剩余数据。 请注意,由 DataOutput 写入的 UTF-8 字符串使用与标准 UTF-8 不同的修改后的格式。

跳过流中的字节

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("datafile.dat"))) {
            
            // Read first value
            int firstValue = dis.readInt();
            System.out.println("First value: " + firstValue);
            
            // Skip 8 bytes
            int skipped = dis.skipBytes(8);
            System.out.println("Skipped " + skipped + " bytes");
            
            // Read next value after skip
            double nextValue = dis.readDouble();
            System.out.println("Next value: " + nextValue);
            
            // Try to skip beyond end of file
            skipped = dis.skipBytes(1000);
            System.out.println("Skipped " + skipped + " bytes at end");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例展示了如何在数据流中跳过字节。 第一个跳过移动到两个值之间的 8 个字节。 第二个跳过尝试跳过 1000 个字节,但仅跳过剩余的字节。 该方法返回实际跳过的字节数,该数量可能少于文件末尾请求的数量。

读取无符号值

DataInput 提供了读取无符号字节和短整型值的方法。 这些在处理使用无符号类型的二进制数据时非常有用。 Java 没有无符号基本类型,因此这些方法返回更宽的类型。

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"))) {
            
            // Read unsigned byte (0-255)
            int unsignedByte = dis.readUnsignedByte();
            System.out.println("Unsigned byte: " + unsignedByte);
            
            // Read unsigned short (0-65535)
            int unsignedShort = dis.readUnsignedShort();
            System.out.println("Unsigned short: " + unsignedShort);
            
            // Read signed and unsigned comparison
            byte signedByte = dis.readByte();
            int anotherUnsigned = dis.readUnsignedByte();
            
            System.out.println("Signed byte: " + signedByte);
            System.out.println("Unsigned byte: " + anotherUnsigned);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了读取无符号值。 readUnsignedByte 返回一个 0-255 范围内的 int,而 readUnsignedShort 返回 0-65535。 该示例显示了有符号和无符号字节值之间的区别。 这些方法在处理使用无符号类型的二进制格式时至关重要。

使用 readLine 读取行

readLine 方法读取以换行符、回车符或 EOF 终止的文本行。 它已被弃用,但对于遗留格式仍然有用。 现代代码应首选 readUTF 或其他文本读取方法。

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("textfile.txt"))) {
            
            // Read lines until EOF
            String line;
            while ((line = dis.readLine()) != null) {
                System.out.println("Line read: " + line);
            }
            
            System.out.println("End of file reached");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例展示了如何使用已弃用的 readLine 方法。 它读取行,直到遇到 null (EOF)。 对于非 ASCII 文本,该方法无法正确地将字节转换为字符。 对于现代代码,请改用 BufferedReader.readLine 进行正确的文本处理。

来源

Java DataInput 接口文档

在本文中,我们通过实际示例介绍了 Java DataInput 接口的所有方法。 了解这些方法对于在 Java 应用程序中使用二进制数据至关重要。

作者

我叫 Jan Bodnar,是一名敬业的程序员,在该领域拥有多年的经验。 我于 2007 年开始撰写编程文章,至今已撰写了 1,400 多篇文章和八本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程