我逐行从大文件中读取文本数据 但我需要读取n-x行(不读最后x行)。
如果不读取整个文件超过1次怎么办呢? (我读行并立即处理它,所以我不能回去)
答案 0 :(得分:6)
您需要使用简单的预读逻辑。
首先读取x
行并将它们放入缓冲区。然后,您可以一次重复读取一行,将其添加到缓冲区的末尾,并处理缓冲区中的第一行。当您到达EOF
时,缓冲区中有x
条未处理的行。
更新:我注意到有关问题的评论和我自己的答案,所以只是为了澄清:我的建议在n
未知时有效。当然应该知道x
。您需要做的就是创建一个简单的缓冲区,然后用x行填充缓冲区,然后开始处理。
关于缓冲区的实现,只要我们讨论Java的内置集合,就可以使用简单的LinkedList
。因为你要在缓冲区中为你放入的每一行拉出一行,ArrayList
对数组索引的不断移位不会很好。一般来说,支持数组的缓冲区必须是循环的,以避免性能不佳。
答案 1 :(得分:6)
在这篇文章中,我将为您提供两种完全不同的方法来解决您的问题,并且根据您的使用情况,其中一种解决方案将比另一种更适合。
备选方案#1
这种方法虽然非常复杂,但内存效率很高,如果您要跳过大量内容,建议使用此方法,因为在处理过程中,您只会在内存中一次存储一行。
这篇文章中的实现可能不是超级优化,但其背后的理论很明确。
您将首先向后读取文件,搜索N个换行符。如果您已成功找到文件中的某个位置,您希望稍后停止处理,则会跳回文件的开头。
备选方案#2
这种方法易于理解且非常直接。在执行期间,您将在内存中存储N行数,其中N是您最后要跳过的行数。
这些行将存储在FIFO容器中(先进先出)。您将最后一条读取行附加到FIFO,然后删除并处理第一个条目。这样,您将始终处理距离文件末尾至少N个条目的行。
这可能听起来很奇怪,但它绝对可行,而且我建议你这样做的方式;首先阅读文件向后。
SKIP_N
换行符以下代码将从42
中删除最后/tmp/sample_file
行,并使用本文前面所述的方法打印其余行。
import java.io.RandomAccessFile;
import java.io.File;
import java.lang.Math;
public class Example {
protected static final int SKIP_N = 42;
public static void main (String[] args)
throws Exception
{
File fileHandle = new File ("/tmp/sample_file");
RandomAccessFile rafHandle = new RandomAccessFile (fileHandle, "r");
String s1 = new String ();
long currentOffset = 0;
long endOffset = findEndOffset (SKIP_N, rafHandle);
rafHandle.seek (0);
while ((s1 = rafHandle.readLine ()) != null) {
; currentOffset += s1.length () + 1; // (s1 + "\n").length
if (currentOffset >= endOffset)
break;
System.out.println (s1);
}
}
protected static long findEndOffset (int skipNLines, RandomAccessFile rafHandle)
throws Exception
{
long currentOffset = rafHandle.length ();
long endOffset = 0;
int foundLines = 0;
byte [] buffer = new byte[
1024 > rafHandle.length () ? (int) rafHandle.length () : 1024
];
while (foundLines < skipNLines && currentOffset != 0) {
currentOffset = Math.max (currentOffset - buffer.length, 0);
rafHandle.seek (currentOffset);
rafHandle.readFully (buffer);
for (int i = buffer.length - 1; i > -1; --i) {
if (buffer[i] == '\n') {
++foundLines;
if (foundLines == skipNLines)
endOffset = currentOffset + i - 1; // we want the end to be BEFORE the newline
}
}
}
return endOffset;
}
}
LinkedList<String>
LinkedList<String>
包含的行数多于您要跳过的行数,请删除第一个条目并对其进行处理import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.DataInputStream;
import java.io.BufferedReader;
import java.util.LinkedList;
public class Example {
protected static final int SKIP_N = 42;
public static void main (String[] args)
throws Exception
{
String line;
LinkedList<String> lli = new LinkedList<String> ();
FileInputStream fis = new FileInputStream ("/tmp/sample_file");
DataInputStream dis = new DataInputStream (fis);
InputStreamReader isr = new InputStreamReader (dis);
BufferedReader bre = new BufferedReader (isr);
while ((line = bre.readLine ()) != null) {
lli.addLast (line);
if (lli.size () > SKIP_N) {
System.out.println (lli.removeFirst ());
}
}
dis.close ();
}
}
答案 2 :(得分:2)
请阅读前面的x
行。这是一个x
行的队列。