ZetCode

Java SequenceInputStream 类

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

java.io.SequenceInputStream 类将多个输入流连接成一个连续的流。 它按顺序从每个输入流中读取数据,直到到达结尾,然后自动切换到下一个输入流。这对于组合多个数据源非常有用。

SequenceInputStream 扩展了 InputStream 并提供了顺序读取功能。 它支持枚举流或一对流。 当到达当前流的 EOF 时,该类会自动处理流切换。

SequenceInputStream 类概述

SequenceInputStream 提供从多个流的顺序读取。 主要方法包括标准的 InputStream 操作,如 read、skip 和 close。 该类管理当前流并在需要时切换。

public class SequenceInputStream extends InputStream {
    public SequenceInputStream(Enumeration<? extends InputStream> e);
    public SequenceInputStream(InputStream s1, InputStream s2);
    public int read();
    public int read(byte[] b, int off, int len);
    public long skip(long n);
    public int available();
    public void close();
}

上面的代码显示了 SequenceInputStream 提供的关键方法。 构造函数接受流的枚举或两个流。 该类自动处理所有流切换和 EOF 检测。

使用两个流创建 SequenceInputStream

创建 SequenceInputStream 最简单的方法是使用两个输入流。 构造函数接受两个 InputStream 对象,并从第一个对象读取直到 EOF,然后切换到第二个对象。 当 SequenceInputStream 关闭时,两个流都会被关闭。

Main.java
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.SequenceInputStream;

public class Main {

    public static void main(String[] args) {
        String data1 = "First part of data. ";
        String data2 = "Second part of data.";
        
        try (ByteArrayInputStream stream1 = new ByteArrayInputStream(data1.getBytes());
             ByteArrayInputStream stream2 = new ByteArrayInputStream(data2.getBytes());
             SequenceInputStream seqStream = new SequenceInputStream(stream1, stream2)) {
            
            int byteData;
            while ((byteData = seqStream.read()) != -1) {
                System.out.print((char) byteData);
            }
            
            System.out.println("\nReading complete");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例将两个 ByteArrayInputStream 合并为一个 SequenceInputStream。 输出显示了来自两个流的连接数据。 try-with-resources 语句确保所有流都正确关闭。 SequenceInputStream 自动处理流之间的转换。

使用枚举创建 SequenceInputStream

对于两个以上的流,请使用 InputStreams 的枚举。 SequenceInputStream 将按枚举顺序读取每个流,直到所有流都耗尽。 这种方法对于组合多个数据源更加灵活。

Main.java
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Vector;

public class Main {

    public static void main(String[] args) {
        Vector<InputStream> streams = new Vector<>();
        streams.add(new ByteArrayInputStream("First ".getBytes()));
        streams.add(new ByteArrayInputStream("Second ".getBytes()));
        streams.add(new ByteArrayInputStream("Third".getBytes()));
        
        Enumeration<InputStream> en = Collections.enumeration(streams);
        
        try (SequenceInputStream seqStream = new SequenceInputStream(en)) {
            int byteData;
            while ((byteData = seqStream.read()) != -1) {
                System.out.print((char) byteData);
            }
            
            System.out.println("\nAll streams read");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示如何使用 Enumeration 来组合三个输入流。 Vector 存储流,Collections.enumeration 创建 Enumeration。 SequenceInputStream 按顺序读取每个流。 关闭 SequenceInputStream 时,所有流都将关闭。

将字节读入数组

为了获得更好的性能,一次将多个字节读入字节数组。 read 方法返回实际读取的字节数。 这适用于 SequenceInputStream 中的流边界。

Main.java
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Vector;

public class Main {

    public static void main(String[] args) {
        Vector<ByteArrayInputStream> streams = new Vector<>();
        streams.add(new ByteArrayInputStream("Part1".getBytes()));
        streams.add(new ByteArrayInputStream("Part2".getBytes()));
        streams.add(new ByteArrayInputStream("Part3".getBytes()));
        
        try (SequenceInputStream seqStream = 
                new SequenceInputStream(streams.elements())) {
            
            byte[] buffer = new byte[5];
            int bytesRead;
            
            while ((bytesRead = seqStream.read(buffer)) != -1) {
                System.out.println("Read " + bytesRead + " bytes: " + 
                    new String(buffer, 0, bytesRead));
            }
            
            System.out.println("All data read");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了从 SequenceInputStream 的批量读取。 缓冲区大小为 5 个字节,与每个部分的长度匹配。 read 方法返回实际读取的字节,该字节可能小于缓冲区大小。 String 构造函数仅转换缓冲区的有效部分。

组合文件流

SequenceInputStream 特别适用于组合文件流。 此示例按顺序读取两个文件,就像它们是一个连续的流一样。 该方法适用于任何输入流组合。

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

public class Main {

    public static void main(String[] args) {
        try (FileInputStream file1 = new FileInputStream("file1.txt");
             FileInputStream file2 = new FileInputStream("file2.txt");
             SequenceInputStream seqStream = new SequenceInputStream(file1, file2)) {
            
            int byteData;
            while ((byteData = seqStream.read()) != -1) {
                System.out.print((char) byteData);
            }
            
            System.out.println("\nBoth files read");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例将两个文件输入流组合成一个顺序流。 SequenceInputStream 在切换到 file2.txt 之前,先完全读取 file1.txt。 所有流都由 try-with-resources 块自动关闭。 这种模式对于将多个文件作为一个单元进行处理非常有用。

跨流跳过字节

skip 方法可在 SequenceInputStream 中的组合流之间使用。 它首先跳过当前流中的字节,然后在需要时继续进入后续流。 返回值指示实际跳过的字节数。

Main.java
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Vector;

public class Main {

    public static void main(String[] args) {
        Vector<ByteArrayInputStream> streams = new Vector<>();
        streams.add(new ByteArrayInputStream("1234567890".getBytes()));
        streams.add(new ByteArrayInputStream("ABCDEFGHIJ".getBytes()));
        
        try (SequenceInputStream seqStream = 
                new SequenceInputStream(streams.elements())) {
            
            // Skip first 5 bytes (from first stream)
            long skipped = seqStream.skip(5);
            System.out.println("Skipped " + skipped + " bytes");
            
            // Read next 5 bytes (remaining from first stream)
            byte[] buffer = new byte[5];
            seqStream.read(buffer);
            System.out.println("After skip: " + new String(buffer));
            
            // Skip 3 bytes into second stream
            skipped = seqStream.skip(3);
            System.out.println("Skipped " + skipped + " more bytes");
            
            // Read remaining from second stream
            seqStream.read(buffer);
            System.out.println("Final read: " + new String(buffer));
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例演示了跨多个流的跳过。 第一个 skip 在第一个流中运行。 第二个 skip 跨越到第二个流。 read 操作验证跳过位置。 skip 方法返回实际跳过的字节数,该字节数可能小于请求的字节数。

SequenceInputStream 中的可用字节

available 方法返回当前流中可用的字节数,而不会阻塞。 它不包括序列中后续流中的字节。 这种行为对于了解流状态很重要。

Main.java
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.Vector;

public class Main {

    public static void main(String[] args) {
        Vector<ByteArrayInputStream> streams = new Vector<>();
        streams.add(new ByteArrayInputStream("Short".getBytes()));
        streams.add(new ByteArrayInputStream("LongerData".getBytes()));
        
        try (SequenceInputStream seqStream = 
                new SequenceInputStream(streams.elements())) {
            
            System.out.println("Initially available: " + 
                seqStream.available() + " bytes");
            
            // Read first stream completely
            byte[] buffer = new byte[10];
            seqStream.read(buffer);
            System.out.println("After first read: " + 
                seqStream.available() + " bytes available");
            
            // Read part of second stream
            seqStream.read(buffer, 0, 3);
            System.out.println("After partial read: " + 
                seqStream.available() + " bytes available");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此示例显示了 available 在 SequenceInputStream 中的行为方式。 最初,它仅报告来自第一个流的字节。 耗尽第一个流后,它将报告来自第二个流的字节。 available 计数随着从当前流中读取数据而减少。

来源

Java SequenceInputStream 类文档

在本文中,我们介绍了 Java SequenceInputStream 类的基本方法和功能。 了解这些概念对于在 Java 应用程序中使用顺序 I/O 操作至关重要。

作者

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

列出所有Java教程