In a Swing application, I sometimes need to support read-only access to large, line-oriented text files that are slow to load: logs, dumps, traces, etc. For small amounts of data, a suitable Document
and JTextComponent
are fine, as shown here. I understand the human limitations of browsing large amounts of data, but the problematic stuff seems like it's always in the biggest file. Is there any practical alternative for larger amounts of text in the 10-100 megabyte, million-line range?
The best way to view extremely large text files is to use… a text editor. Not just any text editor, but the tools meant for writing code. Such apps can usually handle large files without a hitch and are free. Large Text File Viewer is probably the simplest of these applications.
Modern editors can handle surprisingly large files. In particular, Vim (Windows, macOS, Linux), Emacs (Windows, macOS, Linux), Notepad++ (Windows), Sublime Text (Windows, macOS, Linux), and VS Code (Windows, macOS, Linux) support large (~4 GB) files, assuming you have the RAM.
While several commercial applications such as Ultra Edit support large text files, it is not necessary to pay money to open these text files on Windows. EditPad Lite -- Has a limit of 2 Gigabytes but supports viewing and editing.
It is a viewer application that supporting browsing and searching text files. Large Text File Viewer -- A free program for Windows that opens large text files just fine. The program loaded the 30 Gigabyte text document just fine. It is a reader application only, however, which means that you may use it to find text and view it but not to edit it.
While most users may never encounter huge text files on any system, those who do need a program that opens these text documents reliably. Neither Notepad nor Wordpad open very large text files, and even favorite third-party alternatives such as Notepad++ won't once file size reaches a certain threshold.
According to the feature listing on the official website, EM Editor supports files with a size of up to 248 Gigabytes. Glogg -- Is a cross-platform program that loads large text files quickly. It is a viewer application that supporting browsing and searching text files.
Because of the size, you'll surely want to load the file in the background to avoid blocking the event dispatch thread; SwingWorker
is a common choice. Instead of using a Document
, consider updating a TableModel
and displaying the lines of text in the rows of a JTable
. This offers several advantages:
Results will begin appearing immediately, and there will be reduced perceived latency.
JTable
uses the flyweight pattern for rendering, which scales well into the multi-megabyte, million-line range.
You can parse the input as it is being read to create an arbitrary column structure.
You can leverage the sorting and filtering features of JTable
, for example.
You can use TablePopupEditor
to focus on a single line.
Addendum: The example below uses DefaultTableModel
for convenience. To reduce overhead, extend AbstractTableModel
and manage a List<String>
or List<RowData>
, as shown here. The example displays indeterminate progress; changes to display intermediate progress are shown here.
Code:
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();
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With