Java - 读取器流中的动态字符串替换

标签 java performance stream

我在磁盘上有一个(文本)文件,我需要将其读入一个带有 Reader 对象的库中。

在读取此文件时,我想对数据执行正则表达式字符串替换。

我目前的解决方案是将整个文件作为一个 String 读入内存,进行 String 替换,然后为该 String 创建一个 StringReader 并将其作为 Reader 传回库。

这可行,但是对于大文件(尤其是在多线程中运行),性能是个问题。

我想做的是让它一次从文件中读取每一行,替换这个子字符串,然后静静地返回给 Reader 的消费者——但我想不出该怎么做。

有没有更好的方法来完成这个任务?

我正在使用 Java 7

下面是我当前解决方案的示例 - 从"file"读取,将所有“a”替换为“b”,然后将 Stream 传递给消费者。

public void loadFile(final File file) throws Exception
{
    final Pattern regexPattern = Pattern.compile("a");
    final String replacementString = "b";

    try (BufferedReader cleanedBufferedReader = new BufferedReader(new StringReader(replaceInBufferedReader(new BufferedReader(new FileReader(file)),
            regexPattern, replacementString))))
    {
        new StreamSource(cleanedBufferedReader).doSomething();
    }
}

private static String replaceInBufferedReader(final BufferedReader reader, final Pattern pattern, final String replacement) throws IOException
{
    final StringBuilder builder = new StringBuilder();
    String str;

    while ((str = reader.readLine()) != null)
    {
        builder.append(str).append(System.lineSeparator());
    }

    return pattern.matcher(builder.toString()).replaceAll(replacement);
}

最佳答案

您只想子类化 BufferedReader。

class MyBufferedReader extends BufferedReader {

    MyBufferedReader(Reader r) {
        super(r);
    }

    @Override
    String readLine() {
        String line = super.readLine();
        // perform replacement here
        return line;
    }

}

像往常一样打开您的文件,但不是将其包装在 BufferedReader 中,而是将其包装在您的子类中。

try ( Reader r = ...;
          BufferedReader br = new MyBufferedReader(r)) {
     String line;
     while ((line = br.readLine()) != null) {
         // use returned line
     }
}

更新

下面是一个 Reader,它允许您逐行替换输入流,同时仍然向用户呈现一个 Reader 界面流。

在内部,原始流被包装在 BufferedReader 中,一次读取一行。可以对已读取的行执行任何所需的转换。转换后的行然后变成 StringReader。当流的用户调用任何 read(...) 操作时,请求被定向到缓冲的 StringReader 以满足。如果 StringReader 用完了字符,则加载并转换 BufferedReader 的下一行,以继续为 read(...)< 提供输入.

abstract public class TranslatingReader extends Reader {

    private BufferedReader input;
    private StringReader output;

    public TranslatingReader(Reader in) {
        input = new BufferedReader(in);
        output = new StringReader("");
    }

    abstract public String translate(String line);

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        int read = 0;

        while (len > 0) {
            int nchars = output.read(cbuf, off, len);
            if (nchars == -1) {
                String line = input.readLine();
                if (line == null) {
                    break;
                }

                line = tranlate(line);

                line += "\n"; // Add the newline which was removed by readLine()
                output = new StringReader(line);
            } else {
                read += nchars;
                off += nchars;
                len -= nchars;
            }
        }

        if (read == 0)
            read = -1;

        return read;
    }

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

关于Java - 读取器流中的动态字符串替换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50799710/

相关文章:

javascript - node.js - 向多个客户端共享同步 mp3 流

java - 使用 XML 的 REST Web 服务

java - 在 C#/Unity 中启动外部 Android 应用程序

java - 如何在 netbeans 中更改 jar 文件?

javascript - 在使用数万个索引的 Javascript 中使用数组是否可取?

Java ByteBuffer 性能问题

performance - O(N) 是什么意思

javascript - 如何将二进制数据从binaryjs转换为字符串/文本

c# - 如何使用 C# 正确创建缩略图?

java - 寻找 H 指数背后的直觉