В этом посте я предоставлю вам два совершенно разных подхода к решению вашей проблемы, и в зависимости от вашего варианта использования одно из решений подойдет лучше, чем другое.
Альтернатива # 1
Этот метод является эффективным с точки зрения памяти, но довольно сложным, если вы собираетесь пропустить много содержимого, этот метод рекомендуется, так как вы будете хранить только одну строку за раз в памяти во время обработки.
Реализация этого в этом посте не может быть супер оптимизированной, но теория, стоящая за этим, ясна.
Вы начнете с чтения файла в обратном направлении, поиска N числа разрывов строк. Когда вы успешно найдете, где в файле вы хотите остановить обработку позже, вы вернетесь к началу файла.
Альтернатива # 2
Этот метод прост для понимания и очень прост. Во время выполнения в памяти будет храниться N строк, где N - количество строк, которые вы хотите пропустить в конце.
Строки будут храниться в контейнере FIFO ( First In, First Out ). Вы добавите последнюю прочитанную строку в FIFO, а затем удалите и обработаете первую запись. Таким образом, вы всегда будете обрабатывать строки как минимум на N записей от конца вашего файла.
Альтернатива # 1
Это может звучать странно, но это определенно выполнимо и способ, которым я бы порекомендовал вам сделать это; начать с чтения файла назад .
- Искать в конец файла
- Считывать (и удалять) байты (в начале файла), пока не найдете
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;
}
}
Альтернатива # 2
- Читать из вашего файла строка за строкой
- В каждой успешно прочитанной строке вставьте строку в конце вашего
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 ();
}
}