Подтвердить что ты не робот

Загрузка и отображение больших текстовых файлов

В приложении Swing мне иногда приходится поддерживать доступ только для чтения к крупным текстовым текстовым файлам, которые медленно загружаются: журналы, дампы, трассировки и т.д. Для небольших объемов данных подходит Document и JTextComponent в порядке, как показано здесь. Я понимаю человеческие ограничения в просмотре больших объемов данных, но проблемный материал кажется всегда в самом большом файле. Есть ли какая-либо практическая альтернатива для больших объемов текста в диапазоне 10-100 мегабайт, миллионный диапазон?

4b9b3361

Ответ 1

Я бы отделил проблему.

Первая модель - скорость построения документа

Второй - это рендеринг документа - создание дерева представлений для представления документа.

Вопрос в том, нужны ли эффекты шрифтов, например раскраски ключевых слов?

Я бы начал с части документа. IMHO чтение файла через EditorKit.read() должно быть быстрым даже для больших файлов. Я хотел бы использовать PainDocument для этой цели и проверить, достаточно ли построена чистая модель для вашего приложения. Если да, то просто используйте модель "Документ". Если не реализовать свой собственный интерфейс Document, потому что AbstractDocument имеет множество методов для обработки обновлений (например, writeLock).

Когда мы загружаем документ достаточно быстро, нам нужно решить его. По умолчанию представления, используемые в javax.swing.text, действительно гибкие. Они разработаны как базовые классы для расширения - таким образом, у нас много кода, который нам не нужен. Например. измерения.

Для этой функции я бы использовал шрифт Monospaced, нам не нужно обертывать, поэтому измерения вида widht бывают быстрым = самая длинная строка char count * char widht.

Высота также char высота * количество строк.

Итак, наш PLainTextViewReplacement работает очень быстро. Также нам не нужно отображать весь вид, а просто фрагмент, видимый в нашей области прокрутки. Таким образом, рендеринг может быть намного быстрее.

Конечно, должно быть много работы, чтобы обеспечить правильную навигацию по каретке, выбор и т.д.

Ответ 2

Из-за размера вы обязательно захотите загрузить файл в фоновом режиме, чтобы избежать блокировки потока отправки событий; SwingWorker является общим выбором. Вместо использования Document рассмотрите обновление TableModel и отображение строк текста в строках JTable. Это дает несколько преимуществ:

  • Результаты начнут появляться сразу, и будет уменьшена воспринимаемая латентность.

  • JTable использует шаблон flyweight для рендеринга, который хорошо масштабируется в диапазоне с несколькими мегабайтами в миллион строк.

  • Вы можете проанализировать ввод, когда он читается, чтобы создать произвольную структуру столбцов.

  • Вы можете использовать сортировку и фильтрацию функций JTable, для пример.

  • Вы можете использовать TablePopupEditor, чтобы сосредоточиться на одной строке.

Приложение: В приведенном ниже примере для удобства используется DefaultTableModel. Чтобы уменьшить служебные данные, расширьте AbstractTableModel и выполните управление List<String> или List<RowData>, как показано здесь, В этом примере отображается неопределенный прогресс; изменения для промежуточного прогресса отображаются здесь.

код:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

/**
 * @see https://stackoverflow.com/a/25526869/230513
 */
public class DisplayLog {

    private static final String NAME = "/var/log/install.log";

    private static class LogWorker extends SwingWorker<TableModel, String> {

        private final File file;
        private final DefaultTableModel model;

        private LogWorker(File file, DefaultTableModel model) {
            this.file = file;
            this.model = model;
            model.setColumnIdentifiers(new Object[]{file.getAbsolutePath()});
        }

        @Override
        protected TableModel doInBackground() throws Exception {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String s;
            while ((s = br.readLine()) != null) {
                publish(s);
            }
            return model;
        }

        @Override
        protected void process(List<String> chunks) {
            for (String s : chunks) {
                model.addRow(new Object[]{s});
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("DisplayLog");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        DefaultTableModel model = new DefaultTableModel();
        JTable table = new JTable(model);
        JProgressBar jpb = new JProgressBar();
        f.add(jpb, BorderLayout.NORTH);
        f.add(new JScrollPane(table));
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        LogWorker lw = new LogWorker(new File(NAME), model);
        lw.addPropertyChangeListener((PropertyChangeEvent e) -> {
            SwingWorker.StateValue s = (SwingWorker.StateValue) e.getNewValue();
            jpb.setIndeterminate(s.equals(SwingWorker.StateValue.STARTED));
        });
        lw.execute();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            new DisplayLog().display();
        });
    }
}