java - sobreescribir - Cargando y mostrando archivos de texto grandes
modificar archivos txt en java (2)
Yo separaría el problema.
El primero es el modelo: velocidad de creación de documentos
El segundo es el renderizado de documentos: construir un árbol de vistas para representar el documento.
Una pregunta es si necesita efectos de fuente como colorización de palabras clave.
Comenzaría desde la parte de construcción de documentos. En mi humilde opinión, leer el archivo a través de EditorKit.read () debería ser rápido incluso para archivos grandes. Yo usaría el PainDocument para este propósito y verificará si el modelo puro está construido lo suficientemente rápido para su aplicación. En caso afirmativo, está bien, simplemente use el documento como modelo. Si no implementa su propia interfaz de documento porque AbstractDocument tiene muchos métodos para el proceso de actualización (por ejemplo, writeLock).
Cuando tenemos el Documento cargado lo suficientemente rápido, tenemos que resolver la representación del Documento. Por defecto, las vistas utilizadas en javax.swing.text son realmente flexibles. Están diseñados como clases base para ser extendidos, por lo tanto, tiene un montón de código que no necesitamos. Por ejemplo, medir
Para la función, utilizaría la fuente de Monospaced, no es necesario envolver, por lo que las medidas de la vista son: rápido = número de caracteres más largo * char widht.
La altura también es altura de carbon * cantidad de líneas.
Entonces, nuestro PLainTextViewReplacement es realmente rápido. Además, no tenemos que representar toda la vista, sino solo un fragmento visible en nuestro panel de desplazamiento. Por lo tanto, la renderización podría ser mucho más rápida.
Por supuesto, debería haber mucho trabajo para proporcionar una navegación, una selección, etc. correctas.
En una aplicación Swing, a veces necesito admitir el acceso de solo lectura a archivos de texto grandes y orientados a la línea que tardan en cargarse: registros, volcados, rastreos, etc. Para pequeñas cantidades de datos, un Document
adecuado y JTextComponent
están bien, como se muestra aquí . Entiendo las limitaciones humanas de explorar grandes cantidades de datos, pero las cosas problemáticas parecen estar siempre en el archivo más grande. ¿Hay alguna alternativa práctica para grandes cantidades de texto en el rango de 10-100 megabytes y millones de líneas?
Debido al tamaño, seguramente querrá cargar el archivo en segundo plano para evitar el bloqueo del hilo de envío del evento ; SwingWorker
es una opción común. En lugar de utilizar un Document
, considere actualizar un modelo de TableModel
y mostrar las líneas de texto en las filas de una JTable
. Esto ofrece varias ventajas:
Los resultados comenzarán a aparecer de inmediato, y habrá una latencia percibida reducida.
JTable
utiliza el patrón de peso mosca para el renderizado , que se adapta bien al rango de millones de líneas de mega megabytes.Puede analizar la entrada mientras se lee para crear una estructura de columnas arbitraria.
Puede aprovechar las funciones de clasificación y filtrado de
JTable
, por ejemplo .Puede usar
TablePopupEditor
para enfocarse en una sola línea.
Adición: El siguiente ejemplo utiliza DefaultTableModel
para su comodidad. Para reducir la sobrecarga , extienda AbstractTableModel
y administre List<String>
o List<RowData>
, como se muestra aquí . El ejemplo muestra un progreso indeterminado; los cambios para mostrar el progreso intermedio se muestran aquí .
Código:
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://.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();
});
}
}