Java 逐行过滤输入流

Java 逐行过滤输入流,java,Java,我正在从AmazonS3检索大型gzip文件。我希望能够动态转换这些文件的每一行,并将输出上传到另一个S3存储桶 upload API以一个作为输入 S3Object s3object = s3.fetch(bucket, key); InputStream is = new GZIPInputStream(s3object.getObjectContent()); // . . . ? s3.putObject(new PutObjectRequest(bucket, key, is,

我正在从AmazonS3检索大型gzip文件。我希望能够动态转换这些文件的每一行,并将输出上传到另一个S3存储桶

upload API以一个作为输入

S3Object s3object = s3.fetch(bucket, key);

InputStream is = new GZIPInputStream(s3object.getObjectContent());

// . . . ?

s3.putObject(new PutObjectRequest(bucket, key, is, metadata));

我相信最有效的方法是创建自己的自定义输入流,将原始输入流转换为另一个输入流。我不太熟悉这种方法,很想了解更多

基本思想如下

new BufferedReader(is).lines()
这不是非常有效,但应该完成这项工作

public class MyInputStream extends InputStream {

    private final BufferedReader input;
    private final Charset encoding = StandardCharsets.UTF_8;
    private ByteArrayInputStream buffer;

    public MyInputStream(InputStream is) throws IOException {
        input = new BufferedReader(new InputStreamReader(is, this.encoding));
        nextLine();
    }

    @Override
    public int read() throws IOException {
        if (buffer == null) {
            return -1;
        }
        int ch = buffer.read();
        if (ch == -1) {
            if (!nextLine()) {
                return -1;
            }
            return read();
        }
        return ch;
    }

    private boolean nextLine() throws IOException {
        String line;
        while ((line = input.readLine()) != null) {
            line = filterLine(line);
            if (line != null) {
                line += '\n';
                buffer = new ByteArrayInputStream(line.getBytes(encoding));
                return true;
            }
        }
        return false;
    }

    @Override
    public void close() throws IOException {
        input.close();
    }

    private String filterLine(String line) {
        // Filter the line here ... return null to skip the line
        // For example:
        return line.replace("ABC", "XYZ");
    }

}
nextLine()。然后
read()
(由上载作业调用)逐个从缓冲区提取字节,并再次调用
nextLine()
,以加载下一行

用作:

s3.putObject(new PutObjectRequest(bucket, key, new MyInputStream(is), metadata));

性能改进还可以实现
int-read(byte[]b,int-off,int-len)
方法(如果cpu使用率很高),并在S3客户端内部不使用缓冲区(我不知道)的情况下使用
BufferedInputStream

这不是非常有效,但应该完成这项工作

public class MyInputStream extends InputStream {

    private final BufferedReader input;
    private final Charset encoding = StandardCharsets.UTF_8;
    private ByteArrayInputStream buffer;

    public MyInputStream(InputStream is) throws IOException {
        input = new BufferedReader(new InputStreamReader(is, this.encoding));
        nextLine();
    }

    @Override
    public int read() throws IOException {
        if (buffer == null) {
            return -1;
        }
        int ch = buffer.read();
        if (ch == -1) {
            if (!nextLine()) {
                return -1;
            }
            return read();
        }
        return ch;
    }

    private boolean nextLine() throws IOException {
        String line;
        while ((line = input.readLine()) != null) {
            line = filterLine(line);
            if (line != null) {
                line += '\n';
                buffer = new ByteArrayInputStream(line.getBytes(encoding));
                return true;
            }
        }
        return false;
    }

    @Override
    public void close() throws IOException {
        input.close();
    }

    private String filterLine(String line) {
        // Filter the line here ... return null to skip the line
        // For example:
        return line.replace("ABC", "XYZ");
    }

}
nextLine()。然后
read()
(由上载作业调用)逐个从缓冲区提取字节,并再次调用
nextLine()
,以加载下一行

用作:

s3.putObject(new PutObjectRequest(bucket, key, new MyInputStream(is), metadata));

性能改进还可以实现
int read(byte[]b,int off,int len)
方法(如果cpu使用率很高),并在S3客户端内部不使用缓冲区(我不知道)的情况下使用
BufferedInputStream

@gygabyte只有40个声誉,他/她不能发表评论
BufferedReader
没有接受
InputStream
的构造函数@gygabyte只有40个声誉,他/她不能发表评论
BufferedReader
没有接受
InputStream
的构造函数。感谢您的帮助。应该
nextLine()可以从
read()调用而不是构造函数?是否指定了内容长度?S3显示为内容长度。这意味着您需要将整个对象缓冲在某个位置或提取两次。在我的实现中,我扩展了FilterInputStream,而不是InputStream,后者还需要实现读取(字节、偏移量、长度)。请记住,这个例子总是添加一个尾随的新行,不管源代码是否有,但这通常是您想要的,但我将此设置为可选。谢谢您的帮助。应该
nextLine()可以从
read()调用而不是构造函数?是否指定了内容长度?S3显示为内容长度。这意味着您需要将整个对象缓冲在某个位置或提取两次。在我的实现中,我扩展了FilterInputStream,而不是InputStream,后者还需要实现读取(字节、偏移量、长度)。请记住,这个例子总是添加一个尾随的新行,不管源代码是否有一行,但这通常是您想要的,但我将其设置为可选。