Если у вас есть какое-то определение того, что составляет «строку» в вашем большом файле, вы можете просто перебирать свой файл побайтно, и при каждом появлении конца или начала строки вы запоминаете текущий индекс.
Например, если у вас есть текстовый файл Unix (т.е. \n
в качестве разделителя строк), это может выглядеть так:
/**
* a simple class encapsulating information about a line in a file.
*/
public static class LineInfo {
LineInfo(number, start, end) {
this.lineNumber = number;
this.startPos = start;
this.endPos = end;
this.length = endPos - startPos;
}
/** the line number of the line. */
public final long lineNumber;
/** the index of the first byte of this line. */
public final long startPos;
/** the index after the last byte of this line. */
public final long endPos;
/** the length of this line (not including the line separators surrounding it). */
public final long length;
}
/**
* creates an index of a file by lines.
* A "line" is defined by a group of bytes between '\n'
* bytes (or start/end of file).
*
* For each line, a LineInfo element is created and put into the List.
* The list is sorted by line number, start positions and end positions.
*/
public static List<LineInfo> indexFileByLines(File f)
throws IOException
{
List<LineInfo> infos = new ArrayList<LineInfo>();
InputStream in = new BufferedInputStream(new FileInputStream(f));
int b;
for(long index = 0, lastStart = 0, lineNumber = 0;
(b = in.read()) >= 0 ;
index++)
{
if(b == '\n') {
LineInfo info = new LineInfo(lineNumber, lastStart, index);
infos.add(info);
lastStart = index + 1;
lineNumber ++;
}
}
return infos;
}
Это предотвращает любое преобразование байтов в символы, таким образом, любые проблемы с кодированием. Он по-прежнему зависит от того, является ли разделитель строк \n
, но может быть параметр для передачи его методу.
(Для файлов DOS / Windows с \r\n
в качестве разделителя условие немного сложнее, поскольку нам нужно было бы либо сохранить предыдущий байт, либо заглянуть в следующий.)
Для более легкого использования, возможно, вместо списка лучше подойдет пара (или тройка) из SortedMap<Long, LineInfo>
.