Java:如何读取文件的最后一个字符
Posted
技术标签:
【中文标题】Java:如何读取文件的最后一个字符【英文标题】:Java: How to read the last chars of a file 【发布时间】:2018-12-23 01:02:33 【问题描述】:如何以最高的磁盘效率读取文件的最后几个字符?
【问题讨论】:
“有可能吗?” 是的! --- Why is “Is it possible to…” a poorly worded question? @Andreas:不,实际上这是不可能的。您只能按顺序读取数据,这与Java无关,而是操作系统限制 @HovercraftFullOfEels 当然有可能。问题是关于“以更高的磁盘效率这样做”,您可以通过随机访问读取最后一个块,处理这些字节(反向),然后读取second-last 块,进程字节,...最后读取第一个块,进程字节。更大的块大小将提高效率。如果您愿意,您甚至可以将字符设置为Reader
。
random-access,这就是我要搜索的内容,谢谢
@LucasNoetzold 如果您的文本文件使用单字节字符集(例如不是 UTF-8),那么“最后 4 个字符”表示“最后 4 个字节”,那么是的,使用 @987654323 @ 只读取最后 4 个字节可能是最快的方式。只有剖析才能确定。
【参考方案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;
【讨论】:
我建议您将“字符”替换为“代码点”,除非您的意思是length
是 char
(UTF-16 代码单元)的数量——然后进入一般问题索引到 Java 的 UTF-16 字符串。此外,如果文件有 BOM,则不应将其包含在返回的文本中——因为它是元数据,而不是文本。否则,很好的答案。
@TomBlodget length
参数是 char
的数量,即返回的String
的期望length()
,这就是为什么javadoc 说“如果前导字符是半代理对”,则返回的字符串可能比请求的短 [...]”。例如。如果文件都是表情符号,并且您要求 9 个字符,它会返回 8 个代理对,即 4 个代码点,如设计。 --- Java 运行时库不支持 UTF-8 的 BOM,即所有 Java 方法都将 BOM 作为常规字符返回。 --- 这种方法没有理由偏离任何一个 Java 标准。以上是关于Java:如何读取文件的最后一个字符的主要内容,如果未能解决你的问题,请参考以下文章