Кодировка UTF-8 для вывода из консоли в JavaFX TextArea
Я хочу перенаправить вывод консоли в JavaFX TextArea, и я следую предложению здесь: JavaFX: перенаправить вывод консоли в TextArea, созданный в SceneBuilder
Я попытался установить кодировку UTF-8 в PrintStream (), но это выглядит не так хорошо . Установка кодировки в UTF-16 немного улучшает ее, но по-прежнему неразборчиво .
В Eclipse IDE предполагаемый текстовый вывод в консоль оказывается нормальным:
KHA khởi đầu phiên giao dịch sáng nay ở mức 23600 điểm, khối lượng giao dịch trong ngày đạt 765 cổ phiếu, tương đương khoảng 18054000 đồng.
Controller.java
public class Controller {
@FXML
private Button button;
public Button getButton() {
return button;
}
@FXML
private TextArea textArea;
public TextArea getTextArea() {
return textArea;
}
private PrintStream printStream;
public PrintStream getPrintStream() {
return printStream;
}
public void initialize() {
textArea.setWrapText(true);
printStream = new PrintStream(new UITextOutput(textArea), true, StandardCharsets.UTF_8);
} // Encoding set to UTF-8
public class UITextOutput extends OutputStream {
private TextArea text;
public UITextOutput(TextArea text) {
this.text = text;
}
public void appendText(String valueOf) {
Platform.runLater(() -> text.appendText(valueOf));
}
public void write(int b) throws IOException {
appendText(String.valueOf((char) b));
}
}
}
UI.java
public class UI extends Application {
@Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Sample.fxml"));
Parent root = loader.load();
Controller control = loader.getController();
stage.setTitle("Title");
stage.setScene(new Scene(root));
stage.show();
control.getButton().setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
try {
System.setOut(control.getPrintStream());
System.setErr(control.getPrintStream());
System.out.println(
"KHA khởi đầu phiên giao dịch sáng nay ở mức 23600 điểm, khối lượng giao dịch trong ngày đạt 765 cổ phiếu, tương đương khoảng 18054000 đồng.");
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Sample.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="339.0" prefWidth="468.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="main.Controller">
<center>
<TextArea fx:id="textArea" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</center>
<right>
<Button fx:id="button" mnemonicParsing="false" onAction="#getButton" text="Button" BorderPane.alignment="CENTER" />
</right>
</BorderPane>
Я все еще новичок в Java, поэтому не знаю, как именно работает PrintStream или OutputStream. Прошу простить меня за незнание.
Мы ценим каждое предложение.
Ответы
Я считаю, что ваша проблема вызвана этим кодом:
public void write(int b) throws IOException {
appendText(String.valueOf((char) b));
}
Это преобразование каждого отдельного байта в символ. Другими словами, предполагается, что каждый символ представлен одним байтом. Это не обязательно правда. Некоторые кодировки, такие как UTF-8 , могут использовать несколько байтов для представления одного символа. Они должны это сделать, если они хотят иметь возможность представлять более 256 символов.
Вам нужно будет правильно декодировать входящие байты. Вместо того, чтобы пытаться сделать это самостоятельно, было бы лучше найти способ использовать что-то вроде BufferedReader
. К счастью, это возможно с помощью PipedInputStream
и PipedOutputStream
. Например:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.io.UncheckedIOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
import static java.nio.charset.StandardCharsets.UTF_8;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
TextArea area = new TextArea();
area.setWrapText(true);
redirectStandardOut(area);
primaryStage.setScene(new Scene(area, 800, 600));
primaryStage.show();
System.out.println(
"KHA khởi đầu phiên giao dịch sáng nay ở mức 23600 điểm, khối lượng giao dịch trong ngày đạt 765 cổ phiếu, tương đương khoảng 18054000 đồng.");
}
private void redirectStandardOut(TextArea area) {
try {
PipedInputStream in = new PipedInputStream();
System.setOut(new PrintStream(new PipedOutputStream(in), true, UTF_8));
Thread thread = new Thread(new StreamReader(in, area));
thread.setDaemon(true);
thread.start();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private static class StreamReader implements Runnable {
private final StringBuilder buffer = new StringBuilder();
private boolean notify = true;
private final BufferedReader reader;
private final TextArea textArea;
StreamReader(InputStream input, TextArea textArea) {
this.reader = new BufferedReader(new InputStreamReader(input, UTF_8));
this.textArea = textArea;
}
@Override
public void run() {
try (reader) {
int charAsInt;
while ((charAsInt = reader.read()) != -1) {
synchronized (buffer) {
buffer.append((char) charAsInt);
if (notify) {
notify = false;
Platform.runLater(this::appendTextToTextArea);
}
}
}
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private void appendTextToTextArea() {
synchronized (buffer) {
textArea.appendText(buffer.toString());
buffer.delete(0, buffer.length());
notify = true;
}
}
}
}
Использование buffer
вышеизложенного - это попытка избежать переполнения потока приложения JavaFX задачами.
Еще кое-что, что вам нужно принять во внимание:
- Поскольку вы используете строковый литерал, убедитесь, что вы сохраняете исходный файл с UTF-8 и компилируете код с помощью
-encoding UTF-8
. - Убедитесь, что шрифт, который вы используете,
TextArea
может отображать все символы, которые вы хотите использовать. - Это возможно также необходимо запустить приложение ,
-Dfile.encoding=UTF-8
но я не уверен. Я этого не сделал, и у меня все еще работало.
Попробуйте установить кодировку JVM по умолчанию на UTF-8.
java -Dfile.encoding=UTF-8 -jar YourJarfile.jar
Для получения дополнительных сведений см. Этот поток: Установка кодировки символов Java по умолчанию
Если вы не хотите экспортировать файл, перейдите в « Настройки Eclipse» > «Общие»> «Рабочая область» и установите для текстового файла кодировку UTF-8 (или желаемую кодировку).
Есть еще несколько деталей: Как изменить кодировку текстового файла по умолчанию в Eclipse