【问题标题】:Java: How to read the last chars of a fileJava:如何读取文件的最后一个字符
【发布时间】:2018-12-23 01:02:33
【问题描述】:

如何以最高的磁盘效率读取文件的最后几个字符?

【问题讨论】:

  • @Andreas:不,实际上这是不可能的。您只能按顺序读取数据,这与Java无关,而是操作系统限制
  • @HovercraftFullOfEels 当然有可能。问题是关于“以更高的磁盘效率这样做”,您可以通过随机访问读取最后一个块,处理这些字节(反向),然后读取second-last 块,进程字节,...最后读取第一个块,进程字节。更大的块大小将提高效率。如果您愿意,您甚至可以将字符设置为 Reader
  • random-access,这就是我要搜索的内容,谢谢
  • @LucasNoetzold 如果您的文本文件使用单字节字符集(例如不是 UTF-8),那么“最后 4 个字符”表示“最后 4 个字节”,那么是的,使用 @987654323 @ 只读取最后 4 个字节可能是最快的方式。只有剖析才能确定。

标签: java file disk


【解决方案1】:

这是一种从 UTF-8 编码的文本文件中读取最后 N 个字符的方法。

/**
 * Reads last {@code length} characters from UTF-8 encoded text file.
 * <p>
 * The returned string may be shorter than requested if file is too
 * short, if the leading character is a half surrogate-pair, or if
 * file has invalid UTF-8 byte sequences.
 * 
 * @param fileName Name of text file to read.
 * @param length Length of string to return.
 * @return String with up to {@code length} characters.
 * @throws IOException if an I/O error occurs.
 */
public static String readLastChars(String fileName, int length) throws IOException {
    // A char can only store characters in the Basic Multilingual Plane, which are
    // encoded using up to 3 bytes each. A character from a Supplemental Plane is
    // encoded using 4 bytes, and is stored in Java as a surrogate pair, ie. 2 chars.
    // Worst case (assuming valid UTF-8) is that file ends with a 4-byte sequence
    // followed by length-1 3-byte sequences, so we need to read that many bytes.
    byte[] buf;
    try (RandomAccessFile file = new RandomAccessFile(fileName, "r")) {
        int bytesToRead = length * 3 + 1;
        buf = new byte[bytesToRead <= file.length() ? bytesToRead : (int) file.length()];
        file.seek(file.length() - buf.length);
        file.readFully(buf);
    }
    // Scan bytes backwards past 'length' characters
    int start = buf.length;
    for (int i = 0; i < length && start > 0; i++) {
        if (buf[--start] < 0) { // not ASCII
            // Locate start of UTF-8 byte sequence (at most 4 bytes)
            int minStart = (start > 3 ? start - 3 : 0);
            while (start > minStart && (buf[start] & 0xC0) == 0x80)
                start--; // Skip UTF-8 continuation byte
            if (start == minStart)
                i++; // 4-byte UTF-8 -> 2 surrogate chars
        }
    }
    // Create string from bytes, and skip first character if too long
    // (text starts with surrogate pair, assuming valid UTF-8)
    String text = new String(buf, start, buf.length - start, StandardCharsets.UTF_8);
    while (text.length() > length)
        text = text.substring(text.offsetByCodePoints(0, 1));
    return text;
}

【讨论】:

  • 我建议您将“字符”替换为“代码点”,除非您的意思是 lengthchar (UTF-16 代码单元)的数量——然后进入一般问题索引到 Java 的 UTF-16 字符串。此外,如果文件有 BOM,则不应将其包含在返回的文本中——因为它是元数据,而不是文本。否则,很好的答案。
  • @TomBlodget length 参数 char 的数量,即返回的String 的期望length(),这就是为什么javadoc 说“如果前导字符是半代理对”,则返回的字符串可能比请求的短 [...]”。例如。如果文件都是表情符号,并且您要求 9 个字符,它会返回 8 个代理对,即 4 个代码点,如设计。 --- Java 运行时库不支持 UTF-8 的 BOM,即所有 Java 方法都将 BOM 作为常规字符返回。 --- 这种方法没有理由偏离任何一个 Java 标准。
猜你喜欢
  • 1970-01-01
  • 2011-06-11
  • 1970-01-01
  • 2015-01-24
  • 2018-06-06
  • 2022-11-27
  • 2019-02-21
  • 2011-05-06
  • 2016-08-23
相关资源
最近更新 更多