【问题标题】:Do any Java stream-input libraries preserve line ending characters?是否有任何 Java 流输入库保留行尾字符?
【发布时间】:2019-03-21 00:55:11
【问题描述】:

我想一次一行地遍历一个文本文件,对内容进行操作,然后将结果流式传输到一个单独的文件中。 BufferedReader.readLine()的课本案例。

但是:我需要将我的行与换行符粘合在一起,如果原始文件没有我的平台的“正确”换行符(Linux 上的 DOS 文件,反之亦然)怎么办?我想我可以在流中提前阅读一下,看看我能找到什么样的行尾,尽管这真的很hacky。

但是:假设我的输入文件没有尾随换行符。我想保持原来的样子。现在我需要在阅读每一行之前先查看下一行的结尾。在这一点上,我为什么要使用一个给我readLine() 的类?

这似乎应该是一个已解决的问题。是否有一个库(或者甚至更好,核心 Java7 类!),它只会让我调用类似于 readLine() 的方法,它从流中返回一行文本,with EOL 字符(s ) 完好无损?

【问题讨论】:

    标签: java inputstream bufferedreader line-endings


    【解决方案1】:

    这是一个逐字符读取字符直到找到行终止符的实现。传入的读者必须支持mark(),所以如果你的不支持,请将其包装在BufferedReader中。

    public static String readLineWithTerm(Reader reader) throws IOException {
        if (! reader.markSupported()) {
            throw new IllegalArgumentException("reader must support mark()");
        }
    
        int code;
        StringBuilder line = new StringBuilder();
    
        while ((code = reader.read()) != -1) {
            char ch = (char) code;
    
            line.append(ch);
    
            if (ch == '\n') {
                break;
            } else if (ch == '\r') {
                reader.mark(1);
                ch = (char) reader.read();
    
                if (ch == '\n') {
                    line.append(ch);
                } else {
                    reader.reset();
                }
    
                break;
            }
        }
    
        return (line.length() == 0 ? null : line.toString());
    }
    

    【讨论】:

    • 我认为这与我最终必须构建的实现大致相同。仍然感到困惑,似乎没有其他人需要这个!
    【解决方案2】:

    更新:

    但是:我需要将我的行与换行符粘合在一起,如果原始文件没有我的平台的“正确”换行符(Linux 上的 DOS 文件,反之亦然)怎么办?我想我可以在流中提前阅读一下,看看我能找到什么样的行尾,尽管这真的很hacky。

    您可以创建具有指定字符集的 BufferedReader。因此,如果文件古怪,则必须提供文件的字符集。 Files.newBufferedReader(Path p, Charset cs)

    是否有一个库(甚至更好,核心 Java7 类!) 让我调用一个类似于 readLine() 的方法,它返回一行 流中的文本,EOL 字符是否完整?

    如果你要读取一个文件,你必须知道它是什么字符集。如果您知道它是什么字符集,那么您不需要 EOL 字符是“完整的”,因为您可以自己添加它。


    来自BufferedReader.readLine

    读取一行文本。行被视为由换行符 ('\n')、回车符 ('\r') 或回车符后紧跟换行符中的任何一种来终止。

    返回: 包含行内容的字符串,不包括任何行终止字符,如果已到达流的末尾,则为 null

    所以BufferedReader.readLine 确实返回任何行终止字符。如果要保留这些字符,可以改用read 方法。

    int size = 1000; // size of file
    
    BufferedReader br = new BufferedReader(new FileReader("file.txt"));
    char[] buf = new char[size];
    br.read(buf, 0, size);
    

    这只是一个简单的例子,但如果文件有行终止,那么它将显示在缓冲区中。

    【讨论】:

    • 也许我需要澄清 OP,但我知道 BufferedReader 中的方法不能满足我的需要。我的意思是,也许有一个 Apache Commons 库或 Guava 中更灵活的东西? Ted 走在了正确的轨道上(如下),但我认为我不能将 StreamTokenizer 扭曲为将整行作为令牌返回(当然我希望被证明是错误的)。
    • 您需要更仔细地重新阅读我的帖子。我在 BufferedReader 中给了你一个方法,做你需要的。您绝对不需要第三方库来读取文件中的每个字符。这是一种基本的 I/O 操作,可以在每种语言中实现。
    • 我的意思是read() 方法只是图片的一部分。当然,我可以填充缓冲区,但是我必须在其中找到行尾,加载更多数据......现在当我到达缓冲区的末尾时会发生什么?我需要加载更多...但是如果一行超过 1000 个字符怎么办?等等等等。现在我基本上正在自己重新实现整个readLine逻辑。并不是说它那么难 或任何东西,我只是不想自己发现所有的边缘情况。这就是为什么我一直要求图书馆...
    • 我更新了我的帖子来回答你的一些问题。但我仍然不完全理解你的问题。这是一个微不足道的 I/O 操作,不需要第三方库。
    • 行尾与字符集无关。 DOS/Windows (\r\n) 行结尾和 Linux/Unix (\n) 行结尾都是完全有效的 ASCII / UTF-8 / 任何东西。关键是我不知道文件的平台(DOS vs Windows)是什么,我想保留它。
    【解决方案3】:

    您应该使用 StreamTokenizer 来更详细地控制输入解析。

    http://docs.oracle.com/javase/7/docs/api/java/io/StreamTokenizer.html

    【讨论】:

    • 看来我必须遍历该行的每个“单词”,这几乎与像@ktm5124 建议的那样分块阅读内容一样痛苦。我真的想要一个界面,一次只给我一行,包括结尾。看来我可能必须自己构建...
    • 我想上次我做了你正在做的事情,我最终将整个文件作为字符串读取,然后在其上使用 StringTokenizer(它支持返回分隔符)。
    • 我现在没有那个选项——它不是一个文件,它是另一个框架交给我的 InputStream。我可以将整个流读入内存,但我不能保证它不会是多个 GB。如果可能的话,我真的需要按流工作:(
    • 我想你可以一次读入一个“块”,然后通过 StringTokenizer 运行每一块。那会有点乱,但可能还不错。
    • 我可以,但是我必须处理在“块”中不适合整个令牌/行的情况,此时我基本上是在写我要问的原始逻辑首先是:(
    猜你喜欢
    • 2012-06-06
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 2011-06-06
    相关资源
    最近更新 更多