【问题标题】:BufferedReader -- read by token instead of readLine()?BufferedReader - 通过令牌而不是 readLine() 读取?
【发布时间】:2016-05-29 04:58:22
【问题描述】:

有没有办法从 BufferedReader 读取,直到它到达一个不是换行符或回车符的字符(这就是 readLine() 所做的)?

我不想读取一行然后拆分。我想忽略换行符和回车,只考虑具有 BufferedReader 性能的特定标记(例如选项卡)。

【问题讨论】:

  • 您可以将 BufferedReader 包装在 Scanner 中。

标签: java bufferedreader


【解决方案1】:

对于这样的事情,你甚至不应该使用 BufferedReader。我会像这样使用 NIO:

public String[] splitContentsBy(String split, File file){
    try{
        byte[] bytes = Files.readAllBytes(file);
        String contents = new String(bytes);
        String[] array = contents.spilt(split);
    }catch(IOException e){
        e.printStackTrace();
    }
}

如果你只想要一个角色,你可以有:

char c = '?'; //A question mark, as an example.
String[] parts = splitContentsBy(String.valueOf(c), new File("file.txt");

【讨论】:

  • 好吧,我同意这可以解决问题,但对于足够大的文本文件(例如服务器日志)可能不是一个好主意
【解决方案2】:

是的。

 BufferedReader br = ...
 StringBuilder sb = new StringBuilder(ESTIMATED_LENGTH);
 int ch;
 while ((ch = br.read()) != -1 && ch != '\t') {
     sb.append(ch);
 } 

在最好的情况下,您将获得几乎与BufferedReader.readLine() 一样好的性能。在最坏的情况下,您会执行一到两个额外的角色副本(我认为)......这对性能来说还不错1

获得与BufferedReader 一样好的性能将需要破解代码BufferedReader 本身......或重写它。

(您尝试扩展 BufferedReader 不起作用,因为您正在从父类调用 private 方法。这是不允许的!如果您要通过更改方法访问来“修复”该问题,那么您可以也只需“克隆”BufferedReader 类并将您的方法添加到其中。当然,您的类不再是 java.io.BufferedReader 或它的子类。)


1 - 作为证明,考虑大局。如果您正在从某个地方读取大量数据,那么性能瓶颈可能是 I/O 或您在读取令牌后对令牌所做的操作。如果不是这种情况,那么您可能应该使用 1) java.nio / CharBuffer,2) 自定义 I/O 堆栈或 3) 另一种编程语言。

【讨论】:

  • 实际上,步骤 1 到 4 表明我正在使用 BufferedReader 的副本,并且所有私有属性和方法都已更改为受保护(步骤 3)
【解决方案3】:

这不是很优雅,但可能有效。

  1. 将 openjdk BufferedReader 源代码复制到另一个包中(JVM 不会让您的类加载器覆盖任何默认的 Java 类)。你可以从这里得到它——http://grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/io/BufferedReader.java/?v=source
  2. 创建一个继承自该 BufferedReader 副本的子类,创建构造函数并覆盖 readLine()。复制原始的 readLine() 实现并粘贴为覆盖的 readLine()
  3. 将阻止编译的超类 (BufferedReeader) 中的所有属性和方法从私有更改为受保护
  4. 将子类 readLine() 中对 \n 和 ]r 的所有提及替换为 \t(这样您将按制表符拆分)

瞧 :-)

这就是最终的样子

import java.io.IOException;
import java.io.Reader;

public class MyBufferedReader extends BufferedReader {

    /**
     * 
     * @param in
     */
    public MyBufferedReader(Reader in) {
        super(in);

    }

    @Override
    String readLine(boolean ignoreLF) throws IOException {
        StringBuffer s = null;
        int startChar;

        synchronized (lock) {
            ensureOpen();
            boolean omitLF = ignoreLF || skipLF;

        bufferLoop:
            for (;;) {

                if (nextChar >= nChars)
                    fill();
                if (nextChar >= nChars) { /* EOF */
                    if (s != null && s.length() > 0)
                        return s.toString();
                    else
                        return null;
                }
                boolean eol = false;
                char c = 0;
                int i;

                /* Skip a leftover '\n', if necessary */
                if (omitLF && (cb[nextChar] == '\t'))
                    nextChar++;
                skipLF = false;
                omitLF = false;

            charLoop:
                for (i = nextChar; i < nChars; i++) {
                    c = cb[i];
                    if (c == '\t') {
                        eol = true;
                        break charLoop;
                    }
                }

                startChar = nextChar;
                nextChar = i;

                if (eol) {
                    String str;
                    if (s == null) {
                        str = new String(cb, startChar, i - startChar);
                    } else {
                        s.append(cb, startChar, i - startChar);
                        str = s.toString();
                    }
                    nextChar++;
                    if (c == '\t') {
                        skipLF = true;
                    }
                    return str;
                }

                if (s == null)
                    s = new StringBuffer(defaultExpectedLineLength);
                s.append(cb, startChar, i - startChar);
            }
        }
    }

}

你可以这样使用它

    MyBufferedReader my = new MyBufferedReader(new InputStreamReader(Main.class.getResourceAsStream("fileWithTabs.txt")));
    String line = null;
    while((line = my.readLine())!=null) {
        System.out.println(line);
    }
    my.close();

对于这样的输入

some string some other string
some third string after a newline   some forth  
and so on

结果是

some string
some other string
some third string after a newline
some forth

and so on

但是,看起来是一个非常麻烦的解决方案,所以我真的很想在这里看到其他聪明的答案

【讨论】:

    【解决方案4】:

    要忽略新行并返回,只需将您的 readLine 参数设置为: 字符串读取线(真); 并实现一个条件来检测标签。

    【讨论】:

      猜你喜欢
      • 2023-03-21
      • 2014-09-26
      • 1970-01-01
      • 1970-01-01
      • 2012-09-30
      • 1970-01-01
      • 2021-09-30
      • 2016-01-03
      相关资源
      最近更新 更多