Encodage UTF-8 pour la sortie de la console vers JavaFX TextArea
Je veux rediriger la sortie de la console vers JavaFX TextArea, et je suis une suggestion ici: JavaFX: Rediriger la sortie de la console vers TextArea qui est créé dans SceneBuilder
J'ai essayé de définir charset sur UTF-8 dans PrintStream (), mais cela ne semble pas très bien . Définir le jeu de caractères sur UTF-16 l'améliore un peu, mais il est toujours illisible .
Dans Eclipse IDE, la sortie de texte supposée dans la console s'avère correcte:
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>
Je suis encore nouveau sur Java, donc je ne sais pas comment fonctionne exactement PrintStream ou OutputStream. Veuillez excuser mon ignorance.
Chaque suggestion est appréciée.
Réponses
Je pense que votre problème est causé par ce code:
public void write(int b) throws IOException {
appendText(String.valueOf((char) b));
}
Il s'agit de convertir chaque octet individuel en caractère. En d'autres termes, il suppose que chaque caractère est représenté par un seul octet. Ce n'est pas forcément vrai. Certains encodages, tels que UTF-8 , peuvent utiliser plusieurs octets pour représenter un seul caractère. Ils doivent le faire s'ils veulent pouvoir représenter plus de 256 caractères.
Vous devrez décoder correctement les octets entrants. Plutôt que d'essayer de le faire vous-même, il serait préférable de trouver un moyen d'utiliser quelque chose comme BufferedReader
. Heureusement, c'est possible avec PipedInputStream
et PipedOutputStream
. Par example:
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;
}
}
}
}
L'utilisation de buffer
ci-dessus est une tentative pour éviter d'inonder le thread d'application JavaFX de tâches.
Quelques autres choses dont vous devez tenir compte:
- Puisque vous utilisez un littéral de chaîne, assurez-vous que vous enregistrez le fichier source avec UTF-8 et que vous compilez le code avec
-encoding UTF-8
. - Assurez-vous que la police que vous utilisez avec le
TextArea
peut représenter tous les caractères souhaités. - Il est possible que vous deviez également exécuter l'application avec,
-Dfile.encoding=UTF-8
mais je ne suis pas sûr. Je ne l'ai pas fait et cela a toujours fonctionné pour moi.
Essayez de définir votre encodage JVM par défaut sur UTF-8.
java -Dfile.encoding=UTF-8 -jar YourJarfile.jar
Pour plus de détails, consultez ce fil: Définition du codage de caractères Java par défaut
Si vous ne souhaitez pas exporter votre fichier, allez dans vos Préférences Eclipse > Général> Espace de travail et définissez l'encodage du fichier texte sur UTF-8 (ou l'encodage que vous souhaitez avoir).
Il y a quelques détails supplémentaires: Comment changer le codage de fichier texte par défaut dans Eclipse