Konsoldan JavaFX TextArea'ya çıktı için UTF-8 kodlaması

Dec 22 2020

Konsol'daki çıktıyı JavaFX TextArea'ya yeniden yönlendirmek istiyorum ve burada bir öneriyi uyguluyorum : JavaFX: Konsol çıktısını SceneBuilder'da oluşturulan TextArea'ya yeniden yönlendir

PrintStream () içinde karakter kümesini UTF-8 olarak ayarlamaya çalıştım, ancak pek iyi görünmüyor . Karakter setini UTF-16 olarak ayarlamak onu biraz iyileştirir, ancak yine de okunaksızdır .

Eclipse IDE'de, Konsoldaki varsayılan metin çıktısı iyi çıkıyor:

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'da hala yeniyim, bu nedenle PrintStream veya OutputStream'in tam olarak nasıl çalıştığını bilmiyorum. Lütfen cehaletimi bağışlayın.

Her öneri takdir edilmektedir.

Yanıtlar

1 Slaw Dec 23 2020 at 03:29

Sanırım sorununun bu koddan kaynaklandığını düşünüyorum:

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

Bu, her bir baytı bir karaktere dönüştürmektir. Başka bir deyişle, her karakterin tek bir bayt ile temsil edildiğini varsaymaktadır. Bu mutlaka doğru değil. UTF-8 gibi bazı kodlamalar, tek bir karakteri temsil etmek için birden çok bayt kullanabilir. 256 karakterden fazlasını temsil edebilmek istiyorlarsa bunu yapmak zorundalar.

Gelen baytların kodunu doğru bir şekilde çözmeniz gerekecek. Bunu kendiniz yapmaya çalışmaktansa, bunun gibi bir şeyi kullanmanın bir yolunu bulmak daha iyi olacaktır BufferedReader. Neyse ki bu PipedInputStreamve ile mümkündür PipedOutputStream. Örneğin:

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

Yukarıdakilerin kullanımı buffer, JavaFX Uygulama İş Parçacığının görevlerle dolmasını önleme girişimidir .

Dikkate almanız gereken diğer şeyler:

  • Dize değişmezi kullandığınız için, hem kaynak dosyayı UTF-8 ile kaydettiğinizden hem de kodu ile derlediğinizden emin olun -encoding UTF-8.
  • Birlikte kullandığınız yazı tipinin, istediğiniz TextAreatüm karakterleri temsil ettiğinden emin olun .
  • Bu var mümkün de birlikte uygulamayı çalıştırmak için gereken -Dfile.encoding=UTF-8ama emin değilim. Yapmadım ve hala benim için çalıştı.
Nickitiki Dec 22 2020 at 15:47

Varsayılan JVM kodlamanızı UTF-8 olarak ayarlamayı deneyin.

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

Daha fazla ayrıntı için şu konu başlığına bakın: Varsayılan Java karakter kodlamasını ayarlama

Dosyanızı dışa aktarmak istemiyorsanız, Eclipse Tercihleri> Genel> Çalışma Alanınıza gidin ve Metin dosyası kodlamasını UTF-8 (veya sahip olmak istediğiniz kodlama) olarak ayarlayın.

Birkaç ayrıntı daha var: Eclipse'de varsayılan metin dosyası kodlaması nasıl değiştirilir?