Как я пишу средство просмотра текстового файла Java для больших файлов журнала

Я работаю над программным продуктом с интегрированным средством просмотра файла журнала. Проблема, его медленное и нестабильное для действительно больших файлов, потому что она читает целый файл в память при просмотре файла журнала. Я желаю записать новое средство просмотра файла журнала, которое решает эту проблему.

Каковы лучшие практики для записи средств просмотра для файлов крупного текста? Как редакторам нравится блокнот ++, и VIM выполняют это? Я думал об использовании буферизированного потокового читателя Двунаправленного текста вместе с TableModel Java. Я думаю вдоль правильных строк, и действительно ли такие потоковые реализации доступны для Java?

- Также Править: Будет стоить пробежать файл однажды для индексации положений запуска каждой строки текста так, чтобы каждый знал, где искать на? Мне, вероятно, будет нужна сумма строк, вероятно, должны просканировать через файл, по крайней мере, однажды?

Edit2: я добавил свою реализацию к ответу ниже. Прокомментируйте его или отредактируйте его, чтобы помочь мне/нам достигнуть большего количества реализации лучшей практики или иначе обеспечьте свое собственное.

11
задан Hannes de Jager 21 May 2010 в 14:30
поделиться

3 ответа

Я не уверен, что NotePad ++ действительно реализует произвольный доступ, но я думаю, что это правильный путь, особенно со средством просмотра файлов журнала, что подразумевает, что он будет доступен только для чтения.

Поскольку ваше средство просмотра журнала будет доступно только для чтения, вы можете использовать файл "stream" с отображением в память произвольного доступа только для чтения. В Java это FileChannel .

Затем просто прыгайте в файле по мере необходимости и визуализируйте на экране просто прокручивающееся окно данных.

Одним из преимуществ FileChannel является то, что параллельные потоки могут открывать файл, и чтение не влияет на текущий указатель файла. Таким образом, если вы добавляете файл журнала в другом потоке, это не повлияет.

Еще одним преимуществом является то, что вы можете вызвать метод размера FileChannel, чтобы получить размер файла в любой момент.

Проблема с отображением памяти непосредственно в файл с произвольным доступом, которую допускают некоторые текстовые редакторы (например, HxD и UltraEdit), заключается в том, что любые изменения напрямую влияют на файл. Следовательно, изменения вносятся немедленно (за исключением кеширования записи), чего пользователи обычно не хотят. Вместо этого пользователи обычно не хотят вносить изменения, пока они не нажмут «Сохранить». Однако, поскольку это всего лишь зритель, у вас нет таких проблем.

4
ответ дан 3 December 2019 в 11:20
поделиться

Я размещаю свою тестовую реализацию (после советов Маркуса Адамса и msw) здесь для вашего удобства, а также для дальнейших комментариев и критики. Это довольно быстро.

Я не беспокоился о безопасности кодирования Unicode. Думаю, это будет мой следующий вопрос. Любые намеки на это очень приветствуются.

class LogFileTableModel implements TableModel {

    private final File f;
    private final int lineCount;
    private final String errMsg;
    private final Long[] index;
    private final ByteBuffer linebuf = ByteBuffer.allocate(1024);
    private FileChannel chan;

    public LogFileTableModel(String filename) {
        f = new File(filename);
        String m;
        int l = 1;
        Long[] idx = new Long[] {};
        try {
            FileInputStream in = new FileInputStream(f);
            chan = in.getChannel();
            m = null;
            idx = buildLineIndex();
            l = idx.length;
        } catch (IOException e) {
            m = e.getMessage();
        }
        errMsg = m;
        lineCount = l;
        index = idx;
    }

    private Long[] buildLineIndex() throws IOException {
        List<Long> idx = new LinkedList<Long>();
        idx.add(0L);

        ByteBuffer buf = ByteBuffer.allocate(8 * 1024);
        long offset = 0;
        while (chan.read(buf) != -1) {
            int len = buf.position();
            buf.rewind();            
            int pos = 0;
            byte[] bufA = buf.array();
            while (pos < len) {
                byte c = bufA[pos++];
                if (c == '\n')
                    idx.add(offset + pos);
            }
            offset = chan.position();
        }
        System.out.println("Done Building index");
        return idx.toArray(new Long[] {});
    }

    @Override
    public int getColumnCount() {
        return 2;
    }

    @Override
    public int getRowCount() {
        return lineCount;
    }

    @Override
    public String getColumnName(int columnIndex) {
        switch (columnIndex) {
        case 0:
            return "#";
        case 1:
            return "Name";
        }
        return "";
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        switch (columnIndex) {
            case 0:                
                return String.format("%3d", rowIndex);
            case 1:
                if (errMsg != null)
                    return errMsg;
                try { 
                    Long pos = index[rowIndex];
                    chan.position(pos);
                    chan.read(linebuf);
                    linebuf.rewind();
                    if (rowIndex == lineCount - 1)
                        return new String(linebuf.array());
                    else    
                        return new String(linebuf.array(), 0, (int)(long)(index[rowIndex+1]-pos));
                } catch (Exception e) {
                    return "Error: "+ e.getMessage();
                }
        }            
        return "a";
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return String.class;
    }

    // ... other methods to make interface complete


}
0
ответ дан 3 December 2019 в 11:20
поделиться

Типичный подход состоит в том, чтобы использовать считыватель файлов с возможностью поиска, сделать один проход по журналу, записывая индекс смещения строк, а затем представить только окно на часть файла по запросу.

Это уменьшает количество данных, необходимых для быстрого вызова, и не загружает виджет, 99% содержимого которого в данный момент не видно.

2
ответ дан 3 December 2019 в 11:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: