Java 如何在Swing中读取和显示大型文本文件?

Java 如何在Swing中读取和显示大型文本文件?,java,swing,file,inputstream,jtextarea,Java,Swing,File,Inputstream,Jtextarea,这听起来可能有点复杂,我会尽量简化我的问题。 我正在开发的程序可以使用JTextArea读写文件。当文件相当大时,将该文件中的数据读入文本区域确实需要很长时间。例如,我有一个文件,目前有40000行文本,大约每行50个字符;此外,有些线条会自动换行。有相当多的文本,它需要更多的时间来阅读从该文件,然后我想 目前,我正在使用标准的读取方法,使用JTextArea组件包含的BufferedReader实例。我想做的是加载JTextArea,在屏幕上加载一定量的文本。屏幕外加载的其余文本在后台的单独线

这听起来可能有点复杂,我会尽量简化我的问题。 我正在开发的程序可以使用
JTextArea
读写文件。当文件相当大时,将该文件中的数据读入文本区域确实需要很长时间。例如,我有一个文件,目前有40000行文本,大约每行50个字符;此外,有些线条会自动换行。有相当多的文本,它需要更多的时间来阅读从该文件,然后我想

目前,我正在使用标准的读取方法,使用
JTextArea
组件包含的
BufferedReader
实例。我想做的是加载
JTextArea
,在屏幕上加载一定量的文本。屏幕外加载的其余文本在后台的单独线程中


使用
InputStream
并将每个字符写入数组,然后将字符写入
JTextArea
是否足够?还是应该有一种不同的方法?我正在努力实现一种快速高效的阅读方法。

目前有两个直接的问题

首先,需要以这样的方式读取文件,以便它可以逐步更新UI,而不会造成不可接受的延迟

其次,
JTextArea
实际处理这些数据量的能力

第一个问题相对来说很容易解决。您需要确保的是,在读取文件时没有阻塞事件调度线程,并且只从事件调度线程的上下文中更新
JTextArea
。为此,
SwingWorker
是一个很好的选择,例如

public class FileReaderWorker extends SwingWorker<List<String>, String> {

    private File file;
    private JTextArea ta;

    public FileReaderWorker(File file, JTextArea ta) {
        this.file = file;
        this.ta = ta;
    }

    public File getFile() {
        return file;
    }

    public JTextArea getTextArea() {
        return ta;
    }

    @Override
    protected List<String> doInBackground() throws Exception {
        List<String> contents = new ArrayList<>(256);
        try (BufferedReader br = new BufferedReader(new FileReader(getFile()))) {
            String text = null;
            while ((text = br.readLine()) != null) {
                // You will want to deal with adding back in the new line characters
                // here if that is important to you...
                contents.add(text);
                publish(text);
            }
        }
        return contents;
    }

    @Override
    protected void done() {
        try {
            get();
        } catch (InterruptedException | ExecutionException ex) {
            ex.printStackTrace();
            // Handle exception here...
        }
    }

    @Override
    protected void process(List<String> chunks) {
        JTextArea ta = getTextArea();
        for (String text : chunks) {
            ta.append(text);
        }
    }

}
公共类FileReaderWorker扩展SwingWorker{
私有文件;
私人住宅区;
公共文件读取器(文件文件,JTextArea ta){
this.file=文件;
this.ta=ta;
}
公共文件getFile(){
返回文件;
}
公共JTextArea getTextArea(){
返回ta;
}
@凌驾
受保护列表doInBackground()引发异常{
列表内容=新的ArrayList(256);
try(BufferedReader br=new BufferedReader(new FileReader(getFile()))){
字符串文本=空;
而((text=br.readLine())!=null){
//您将需要处理添加回新行字符的问题
//如果这对你很重要的话。。。
内容。添加(文本);
出版(文本);
}
}
返回内容;
}
@凌驾
受保护的void done(){
试一试{
get();
}捕获(InterruptedException | ExecutionException ex){
例如printStackTrace();
//在这里处理异常。。。
}
}
@凌驾
受保护的无效进程(列表块){
JTextArea ta=getTextArea();
for(字符串文本:块){
ta.追加(文本);
}
}
}
查看和了解更多详细信息

ps-您不需要使用
列表
来存储内容,我只是作为一个示例

public class FileReaderWorker extends SwingWorker<List<String>, String> {

    private File file;
    private JTextArea ta;

    public FileReaderWorker(File file, JTextArea ta) {
        this.file = file;
        this.ta = ta;
    }

    public File getFile() {
        return file;
    }

    public JTextArea getTextArea() {
        return ta;
    }

    @Override
    protected List<String> doInBackground() throws Exception {
        List<String> contents = new ArrayList<>(256);
        try (BufferedReader br = new BufferedReader(new FileReader(getFile()))) {
            String text = null;
            while ((text = br.readLine()) != null) {
                // You will want to deal with adding back in the new line characters
                // here if that is important to you...
                contents.add(text);
                publish(text);
            }
        }
        return contents;
    }

    @Override
    protected void done() {
        try {
            get();
        } catch (InterruptedException | ExecutionException ex) {
            ex.printStackTrace();
            // Handle exception here...
        }
    }

    @Override
    protected void process(List<String> chunks) {
        JTextArea ta = getTextArea();
        for (String text : chunks) {
            ta.append(text);
        }
    }

}
第二个问题要复杂得多,需要一些额外的测试来确保它实际上是一个问题,但一般来说,超过1mb的内容往往会导致问题

为此,您需要能够管理
JScrollPane
,能够向后和向前请求文件中的文本块,并尝试有效地“篡改”该过程(这样,您只需要加载所需的文本,但仍然可以使其看起来像是在
JTextArea
中加载了所有文本)

您还可以看看
FileChannel
,它提供了比标准
java.io
类更多的功能,包括内存映射,对于初学者,请看一看


您也可以考虑使用“代码> JSList或JTab> /Cord>,以显示大量数据。这是有局限性的,因为有固定行高的期望,当改变时(动态行高)会影响性能,但可能是一个合适的选择…

(FWIW:2MB文件对于今天的硬件来说不是很“大”——也就是说,它运行得太慢了吗?对于真正大的文件,还有更好的方法。)好吧,它实际上是4.20 mb大,但我同意。但是,它仍然需要比我喜欢的更长的时间来加载。使用BufferedReader(包装输入流)时,顺序IO应该是“几乎即时的”.加载时间(IO)和加载时间(UI)看看是什么引入了不希望出现的延迟。好吧,我明白了。我目前正在使用一个BufferedReader和一个包装文件读取器。那么InputStream会更高效吗?几乎可以肯定的是,问题不在于读取文件,而在于试图让JTextArea处理数据。你可以进行某种手动分页,只需设置一个证书a将数据的子集放入jtextarea。我会尝试使用
JList
JTable
查看视图,以利用flyweight渲染。@绝对是垃圾神查看,如果OP希望能够编辑值,它会变得稍微复杂一些,但并非不可能……很好;默认的
JTable
editor就足够了,但写回可能会很乏味。还有固定和动态行高的问题,固定行高的组件得到了很好的优化,动态行高意味着组件需要测试每一行,以便能够计算组件的高度,如果仔细做,更新可以做得很好,但它是要记住的一点是。。。