Можете ли вы переместить сканер в место в файле или выполнить сканирование в обратном направлении?

У меня очень большой текстовый файл, и мне нужно собрать данные где-то ближе к концу. Возможно, Scanner не лучший способ сделать это, но было бы очень расточительно начинать сверху и захватывать 6000 строк, прежде чем добраться до интересующей меня части файла. Есть ли способ либо сказать Scanner перейти к скажем, 7/8 вниз по документу или начать снизу и сканировать вверх, захватывая строку за строкой?

Спасибо


person Mike    schedule 17.06.2010    source источник
comment
6000 строк не так уж и много. Ты это пробовал? Достаточно ли часто это выполняется, чтобы стоило все усложнять?   -  person LanceH    schedule 17.06.2010
comment
6000 — это просто мой разбавленный текстовый файл. Я обеспокоен гораздо большими файлами в этой области. Я также уделяю большое внимание быстродействию программ и не хочу задерживать систему какой-либо обработкой, в которой она на самом деле не нуждается.   -  person Mike    schedule 17.06.2010


Ответы (3)


Основным источником ввода для java.util.Scanner является java.lang.Readable. Помимо конструктора Scanner(File), Scanner не знает и не заботится о том, что он сканирует файл.

Кроме того, поскольку это регулярное выражение, основанное на java.util.regex.*, оно не может сканировать назад.

Чтобы выполнить то, что вы хотите сделать, лучше всего сделать это на уровне источника ввода, например. с помощью InputStream.skip исходного кода перед передачей его конструктору Scanner.


On Scanner.skip

Scanner сам имеет skip, а такой шаблон, как "(?s).{10}", будет пропускать 10 символов (в (?s) однострочном/Pattern.DOTALL), но это, возможно, довольно окольный способ сделать это.

Вот пример использования skip для пропуска заданного количества строк.

    String text =
        "Line1 blah blah\n" +
        "Line2 more blah blah\n" +
        "Line3 let's try something new \r\n" +
        "Line4 meh\n" + 
        "Line5 bleh\n" + 
        "Line6 bloop\n";
    Scanner sc = new Scanner(text).skip("(?:.*\\r?\\n|\\r){4}");
    while (sc.hasNextLine()) {
        System.out.println(sc.nextLine());
    }

Это печатает (как видно на ideone.com):

Line5 bleh
Line6 bloop
person polygenelubricants    schedule 17.06.2010
comment
Спасибо за ответ. Думаю, я пропустил функцию пропуска в списке API сканера. Я думаю, что воспользуюсь преимуществами InputStream.skip. - person Mike; 17.06.2010
comment
@Mike: да, Марк Питерс на высоте. Если вы знаете, сколько байтов вы хотите пропустить, пропустите на уровне InputStream. Если вы этого не сделаете, например. вы хотите пропустить некоторое количество строк, а ввод достаточно динамичен, чтобы вы не могли предварительно обработать его, чтобы создать из него индекс, тогда просто Scanner.skip. Излишне говорить, что этот метод пропускает путем сопоставления входных данных, так что на самом деле он выполняет довольно много работы. - person polygenelubricants; 17.06.2010
comment
Часть skip дает мне java.lang.StackOverflowError, когда я пытаюсь указать аргумент вместо 4 в статическом методе. - person Hooli; 10.10.2016

Scanner оборачивает InputStream, вы можете использовать метод skip(long) потока, чтобы пропустить ненужные строки, а затем начать сканирование.

Подробнее читайте в InputStream javadoc

person RonK    schedule 17.06.2010
comment
Очевидная трудность заключается в том, что skip пропускает не строки, а пропускает байты, и невозможно определить, сколько байтов содержится в каждой строке, не читая их. Но это хороший способ пропустить некоторые данные. - person Mark Peters; 17.06.2010
comment
@Mark Peters: Отличный комментарий - я не принял это во внимание. - person RonK; 17.06.2010
comment
Это все еще очень полезно для меня. Спасибо вам за помощь. - person Mike; 17.06.2010

Вместо этого вам следует использовать RandomAccessFile.

person Ben S    schedule 17.06.2010
comment
Однако RandomAccessFile бесполезен, если содержимое нужно читать последовательно. - person Amalgovinus; 14.10.2014