我编写了一个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()
}
}
希望你有个主意。提前谢谢你,
哈尼
答案 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()
自动进行刷新。
@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