PrintWriter忽略除最后一行

时间:2017-01-03 14:41:08

标签: java logging swingworker filewriter printwriter

我编写了一个Java Swing程序,它在串口侦听(我使用JSerialComm library)。程序应该在控制台中显示已接收的数据(已经工作),在textarea-field(也可以工作)和文件中显示(不起作用)。

按下按钮开始接收过程,然后按另一个按钮结束。

我使用 SwingWorker 类将GUI更改放入事件派发线程中。串行端口的配置,打开和读取发生在doInBackground()方法中。读取是一个无限的while循环,它嵌入在另一个测试isCancelled()的while循环中。通过按下GUI中的按钮,取消操作是triggert。

textarea和控制台中的输出在process()方法中进行。 done()方法只是执行一些启用/禁用GUI元素并存储PrintWriter close()方法。

为了在文件中写入,我使用FileWriter / PrintWriter(在process()方法中)。

结果:我收到文件中最后发送的一行。 previos sent line被忽略(仅在文件中)。例如。我通过终端程序通过串行连接发送“一个”“两个”“三个”(行结束= LF,CR或CR-LF没有区别)。我只是在文件中收到“三”行。在GUI和控制台上,我按预期收到了完整的3个字符串。

我的相关缩短代码(整个代码位于GitHub,分支“logfile”):

public class SerialPrinter extends JFrame {

    PrintWriter pw;

    private class SerialReadTask extends SwingWorker<Boolean, String> {
        protected Boolean doInBackground() {
            // [Omitted code] Get values from the GUI an open serial port ....
            // Reading serial data
            Scanner serialScanner = new Scanner(chosenPort.getInputStream());
            while (!isCancelled()) {
                while (serialScanner.hasNextLine()) {
                    String line = serialScanner.nextLine();
                    publish(line);
                }
            }
            return false; // Returns true if cannot open serial port (code not here)
        }

        protected void process(List<String> chunk) {
            try {
                pw = new PrintWriter(new FileWriter(tf_Logfile.getText()));
                for (String line : chunk) {
                    pw.println(line); // save to file
                    ta_VirtualPrint.append(line + "\n"); // display in GUI => WORKS!!!
                    System.out.println(line); // print on console => WORKS!!!
                }
            } catch (IOException ex) {
            }
        }

        protected void done() {
            // [Omitted code] Disabling some GUI elemts. Usage of get()<Boolean>    
            if (pw != null) { // if PrintWriter bw exists
                pw.close(); // Close but just get the last submitted line in the file
            }
        }

        private void btn_OpenPortActionPerformed(ActionEvent e) [
            serialReader.execute()
        }

        private void btn_ClosePortActionPerformed(ActionEvent e) [
            serialReader.cancel()
        }
}

希望你有个主意。提前谢谢你,

哈尼

2 个答案:

答案 0 :(得分:0)

您为每一行致电publish

publish(line);

因此,每次用一行覆盖文件时,最后都会写入最后一行读取行。

您可以考虑填充List<String>所有读取行,然后填充convert the list to an array,并使用此数组调用publish

    while (!isCancelled()) {

        List<String> data = new ArrayList<String>();

        while (serialScanner.hasNextLine()) {
            String line = serialScanner.nextLine();
            data.add(line);
        }

        publish(data.toArray(new String[data.size()]));
    }

或者,您可以按原样保留代码,只需在追加模式下创建FileWriter

pw = new PrintWriter(new FileWriter(tf_Logfile.getText(), true));

答案 1 :(得分:0)

谢谢Markus,Jorn和Berger。

@Markus:我之前尝试过你的建议,并没有解决问题。我把pw.flush()和pw.close()放在很多不同的地方:-(最后我省略了flush(),因为它没有区别,close()自动进行刷新。

@Jorn:我也试过你的建议。但是将true作为FileWriter的第二个参数提交只是将当前程序运行的数据附加到之前运行的数据中。正如马库斯所说,冲洗不会成功。

@Berger:是的我发布()每一行。我希望在接收后立即看到传输线(在屏幕上),而不是在完整传输结束时。因此,后台线程的当前数据在后台任务运行时发送到EDT。否则,textarea和console中的输出将无法正常工作。但他们这样做。无论如何,我找到了一个解决方案(参见下面的代码)。但最后我还不明白为什么我的第一种方法不起作用。所以我稍后会考虑你的建议。您发布的代码不会在屏幕(GUI,控制台)和文件中创建任何数据。请不要误会我的意思。谢谢你的努力。

我的解决方案:

我将File / PrintWriter放在后台任务而不是EDT(progress())任务中,请参阅下面的代码。添加的行标有// NEW

protected Boolean doInBackground() throws IOException { // NEW Exception 
            // [Omitted code] Get values from the GUI an open serial port ....
            // Reading serial data
            pw = new PrintWriter(new FileWriter(tf_Logfile.getText())); // NEW
            Scanner serialScanner = new Scanner(chosenPort.getInputStream());
            while (!isCancelled()) {
                while (serialScanner.hasNextLine()) {
                    String line = serialScanner.nextLine();
                    publish(line);
                    pw.println(line); // NEW
                }
            }
            return false; // Returns true if cannot open serial port (code not here)
        }

pw.close()仍然在done()方法中发生。

无论如何,正如我之前提到的,这看起来或多或少是一种解决方法,因为我不明白为什么第一种方法不适用于文件而是用于屏幕输出。

无论如何,在som重构之后=&gt; GitHub