कंसोल से JavaFX TextArea तक आउटपुट के लिए UTF-8 एन्कोडिंग

Dec 22 2020

मैं JavaFX TextArea में कंसोल में आउटपुट को पुनर्निर्देशित करना चाहता हूं, और मैं यहां एक सुझाव का पालन करता हूं: JavaFX: TextBrea के लिए रीडायरेक्ट कंसोल आउटपुट जो SceneBuilder में बनाया गया है

मैंने PrintStream () में UTF-8 के लिए charset सेट करने की कोशिश की, लेकिन यह इतना अच्छा नहीं लगता है । UTF-16 को चारसेट सेट करने से इसमें थोड़ा सुधार होता है, लेकिन यह अभी भी गैरकानूनी है ।

ग्रहण आईडीई में, कंसोल में कथित पाठ आउटपुट ठीक निकलता है:

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.

नियंत्रक.जावा

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);
    }
}

सैंपल .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>

मैं अभी भी जावा के लिए नया हूं इसलिए मैं इस बात से अपरिचित हूं कि प्रिंटस्ट्रीम या आउटपुटस्ट्रीम कैसे काम करता है। कृपया मेरी अज्ञानता का बहाना करो।

हर सुझाव की सराहना की है।

जवाब

1 Slaw Dec 23 2020 at 03:29

मेरा मानना ​​है कि आपकी समस्या इस कोड के कारण है:

public void write(int b) throws IOException {
    appendText(String.valueOf((char) b));
}

यह प्रत्येक व्यक्ति बाइट को एक वर्ण में परिवर्तित कर रहा है। दूसरे शब्दों में, यह मान रहा है कि प्रत्येक चरित्र एक एकल बाइट द्वारा दर्शाया गया है। यह जरूरी नहीं कि सच हो। कुछ एनकोडिंग, जैसे कि यूटीएफ -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 एप्लिकेशन थ्रेड को बाढ़ से बचाने का एक प्रयास है।

कुछ अन्य बातों पर ध्यान देने की आवश्यकता है:

  • चूंकि आप एक स्ट्रिंग शाब्दिक का उपयोग कर रहे हैं, सुनिश्चित करें कि आप दोनों यूटीएफ -8 के साथ स्रोत फ़ाइल को सहेज रहे हैं और कोड को संकलित कर रहे हैं -encoding UTF-8
  • सुनिश्चित करें कि आप जिस फ़ॉन्ट का उपयोग करते हैं, TextAreaवह उन सभी वर्णों का प्रतिनिधित्व कर सकता है जिन्हें आप चाहते हैं।
  • यह संभव है कि आपको एप्लिकेशन को भी चलाना होगा -Dfile.encoding=UTF-8लेकिन मुझे यकीन नहीं है। मैंने नहीं किया और यह अभी भी मेरे लिए काम कर रहा है।
Nickitiki Dec 22 2020 at 15:47

अपने डिफ़ॉल्ट JVM एन्कोडिंग को UTF-8 में सेट करने का प्रयास करें।

java -Dfile.encoding=UTF-8 -jar YourJarfile.jar

अधिक जानकारी के लिए इस थ्रेड को देखें: डिफ़ॉल्ट जावा कैरेक्टर एन्कोडिंग सेट करना

यदि आप अपनी फ़ाइल को निर्यात नहीं करना चाहते हैं, तो अपनी ग्रहण वरीयताएँ> सामान्य> कार्यक्षेत्र में जाएँ और पाठ फ़ाइल को UTF-8 (या एन्कोडिंग जो आप करना चाहते हैं) में सेट करें।

कुछ और विवरण हैं: ग्रहण में डिफ़ॉल्ट पाठ फ़ाइल एन्कोडिंग को कैसे बदलना है