Java流式处理

在 Java 中,没有直接类似 Python 生成器的语法,但可以通过迭代器(Iterator)和流式处理(如使用 Spliterator 或 Reactive Streams)来实现类似生成器的功能。此外,也可以通过 BlockingQueue 和线程的组合实现异步文件解压流。

以下是几种实现方式:

**方法 1:使用 ****Iterator**

实现一个 Iterator,在每次调用 next() 时返回解压完成的下一个文件名称。

import java.io.File;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class FileExtractor implements Iterator<String> {
    private ZipInputStream zipInputStream;
    private ZipEntry currentEntry;

    public FileExtractor(String zipFilePath) throws IOException {
        this.zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));
        this.currentEntry = zipInputStream.getNextEntry();
    }

    @Override
    public boolean hasNext() {
        return currentEntry != null;
    }

    @Override
    public String next() {
        String fileName = currentEntry.getName();
        try {
            // 解压当前文件(简化为输出文件名)
            System.out.println("Extracting: " + fileName);
            zipInputStream.closeEntry();
            currentEntry = zipInputStream.getNextEntry();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return fileName;
    }

    public void close() throws IOException {
        zipInputStream.close();
    }

    public static void main(String[] args) throws IOException {
        try (FileExtractor extractor = new FileExtractor("example.zip")) {
            while (extractor.hasNext()) {
                System.out.println("Extracted file: " + extractor.next());
            }
        }
    }
}

方法 2:使用 **BlockingQueue** + 生产者-消费者模型

使用 BlockingQueue 来将文件名逐个传递给调用者,调用者阻塞等待每个文件名的返回。

import java.io.FileInputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class FileExtractorProducerConsumer {
    private final BlockingQueue<String> queue = new LinkedBlockingQueue<>();
    private final Thread producerThread;

    public FileExtractorProducerConsumer(String zipFilePath) {
        producerThread = new Thread(() -> {
            try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath))) {
                ZipEntry entry;
                while ((entry = zipInputStream.getNextEntry()) != null) {
                    queue.put(entry.getName());
                    System.out.println("Extracting: " + entry.getName());
                    zipInputStream.closeEntry();
                }
                queue.put("EOF"); // Signal end of processing
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        producerThread.start();
    }

    public String nextFile() throws InterruptedException {
        String fileName = queue.take();
        if ("EOF".equals(fileName)) {
            return null;
        }
        return fileName;
    }

    public void close() throws InterruptedException {
        producerThread.join();
    }

    public static void main(String[] args) throws Exception {
        FileExtractorProducerConsumer extractor = new FileExtractorProducerConsumer("example.zip");

        String fileName;
        while ((fileName = extractor.nextFile()) != null) {
            System.out.println("Processed file: " + fileName);
        }

        extractor.close();
    }
}

**方法 3:使用 **Stream** 和 ****Spliterator**

通过 StreamSpliterator 提供懒加载的解压文件流。

import java.io.FileInputStream;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class FileExtractorStream implements Spliterator<String> {
    private final ZipInputStream zipInputStream;
    private ZipEntry currentEntry;

    public FileExtractorStream(String zipFilePath) throws Exception {
        this.zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath));
        this.currentEntry = zipInputStream.getNextEntry();
    }

    @Override
    public boolean tryAdvance(Consumer<? super String> action) {
        if (currentEntry == null) {
            return false;
        }
        action.accept(currentEntry.getName());
        try {
            zipInputStream.closeEntry();
            currentEntry = zipInputStream.getNextEntry();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return currentEntry != null;
    }

    @Override
    public Spliterator<String> trySplit() {
        return null; // Single-threaded processing
    }

    @Override
    public long estimateSize() {
        return Long.MAX_VALUE;
    }

    @Override
    public int characteristics() {
        return NONNULL | ORDERED;
    }

    public void close() throws Exception {
        zipInputStream.close();
    }

    public static void main(String[] args) throws Exception {
        try (FileExtractorStream extractor = new FileExtractorStream("example.zip")) {
            extractor.stream().forEach(fileName -> System.out.println("Extracted: " + fileName));
        }
    }

    public java.util.stream.Stream<String> stream() {
        return java.util.stream.StreamSupport.stream(this, false);
    }
}

方法 4:异步支持(CompletableFuture + 阻塞队列)

如果需要异步支持,可以结合 CompletableFuture 实现。

import java.io.*;
import java.util.concurrent.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class AsyncFileExtractor {
    private final BlockingQueue<CompletableFuture<String>> queue = new LinkedBlockingQueue<>();
    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    public AsyncFileExtractor(String zipFilePath, String outputDir) {
        executor.submit(() -> {
            try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFilePath))) {
                ZipEntry entry;
                byte[] buffer = new byte[1024];

                while ((entry = zipInputStream.getNextEntry()) != null) {
                    CompletableFuture<String> future = new CompletableFuture<>();
                    queue.put(future);

                    File outputFile = new File(outputDir, entry.getName());
                    outputFile.getParentFile().mkdirs();

                    try (FileOutputStream fos = new FileOutputStream(outputFile)) {
                        int len;
                        while ((len = zipInputStream.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                    }

                    System.out.println("Extracted and written: " + outputFile.getAbsolutePath());
                    future.complete(outputFile.getAbsolutePath());
                    zipInputStream.closeEntry();
                }
                queue.put(CompletableFuture.completedFuture(null)); // EOF
            } catch (Exception e) {
                queue.put(CompletableFuture.failedFuture(e));
            }
        });
    }

    public CompletableFuture<String> nextFile() throws InterruptedException {
        return queue.take();
    }

    public void close() {
        executor.shutdown();
    }

    public static void main(String[] args) throws Exception {
        String zipFilePath = "example.zip";
        String outputDir = "output";

        AsyncFileExtractor extractor = new AsyncFileExtractor(zipFilePath, outputDir);

        CompletableFuture<String> future;
        while ((future = extractor.nextFile()).get() != null) {
            System.out.println("Processed file: " + future.get());
        }

        extractor.close();
    }
}

对比总结

  • **Iterator**: 简单直接,适合单线程拉取。
  • **BlockingQueue**: 适合生产者-消费者模式,支持多线程并发处理。
  • **Stream**** 和 ****Spliterator**: 流式懒加载,语法更简洁,更现代。
  • Async + CompletableFuture: 支持异步处理,适合复杂应用场景。

选择实现方式取决于你是否需要多线程支持,以及调用方的消费方式。

你可能感兴趣的:(java,生成器,迭代器,stream,流式处理)