Como salvar caracteres chineses para o arquivo com java?

votos
10

Eu uso o seguinte código para salvar caracteres chineses em um arquivo .txt, mas quando eu abri-lo com Wordpad, eu não poderia lê-lo.

StringBuffer Shanghai_StrBuf = new StringBuffer(\u4E0A\u6D77);
boolean Append = true;

FileOutputStream fos;
fos = new FileOutputStream(FileName, Append);
for (int i = 0;i < Shanghai_StrBuf.length(); i++) {
    fos.write(Shanghai_StrBuf.charAt(i));
}
fos.close();

O que eu posso fazer ? Eu sei que se eu cortar e colar os caracteres chineses no WordPad, posso salvá-lo em um arquivo .txt. Como posso fazer isso em Java?

Publicado 20/04/2009 em 00:20
fonte usuário
Em outras línguas...                            


6 respostas

votos
10

Existem vários fatores no trabalho aqui:

  • arquivos de texto não têm metadados intrínseca para descrever sua codificação (para toda a conversa de impostos de ângulo do suporte, há razões XML é popular)
  • A codificação padrão para o Windows ainda é um 8bit (ou doublebyte) " ANSI caráter" set com uma gama limitada de valores - arquivos de texto escritos neste formato não são portáteis
  • Para dizer um arquivo Unicode de um arquivo ANSI, aplicativos do Windows contam com a presença de uma marca de ordem de byte no início do arquivo ( não estritamente verdadeiro - Raymond Chen explica ). Em teoria, o BOM está lá para dizer a endianess (ordem de bytes) dos dados. Para UTF-8, mesmo que haja apenas uma ordem de byte, os aplicativos do Windows contar com os bytes marcador para determinar automaticamente que é Unicode (embora você vai notar que o bloco de notas tem uma opção de codificação em seu Open / Save diálogos).
  • É errado dizer que Java está quebrado porque não escrever uma BOM UTF-8 automaticamente. Em sistemas Unix, seria um erro para escrever um BOM para um arquivo script, por exemplo, e muitos sistemas Unix usar UTF-8 como a sua codificação padrão. Há momentos em que você não deseja-lo no Windows, também, como quando você está anexando dados para um arquivo existente:fos = new FileOutputStream(FileName,Append);

Aqui é um método de anexar de forma confiável de dados UTF-8 para um arquivo:

  private static void writeUtf8ToFile(File file, boolean append, String data)
      throws IOException {
    boolean skipBOM = append && file.isFile() && (file.length() > 0);
    Closer res = new Closer();
    try {
      OutputStream out = res.using(new FileOutputStream(file, append));
      Writer writer = res.using(new OutputStreamWriter(out, Charset
          .forName("UTF-8")));
      if (!skipBOM) {
        writer.write('\uFEFF');
      }
      writer.write(data);
    } finally {
      res.close();
    }
  }

Uso:

  public static void main(String[] args) throws IOException {
    String chinese = "\u4E0A\u6D77";
    boolean append = true;
    writeUtf8ToFile(new File("chinese.txt"), append, chinese);
  }

Nota: se o arquivo já existia e que você escolheu para acrescentar e os dados existentes não era UTF-8 codificado, a única coisa que o código irá criar é uma bagunça.

Aqui é o Closertipo utilizado neste código:

public class Closer implements Closeable {
  private Closeable closeable;

  public <T extends Closeable> T using(T t) {
    closeable = t;
    return t;
  }

  @Override public void close() throws IOException {
    if (closeable != null) {
      closeable.close();
    }
  }
}

Este código faz uma melhor palpite de estilo do Windows sobre como ler o arquivo com base em marcas de ordem de bytes:

  private static final Charset[] UTF_ENCODINGS = { Charset.forName("UTF-8"),
      Charset.forName("UTF-16LE"), Charset.forName("UTF-16BE") };

  private static Charset getEncoding(InputStream in) throws IOException {
    charsetLoop: for (Charset encodings : UTF_ENCODINGS) {
      byte[] bom = "\uFEFF".getBytes(encodings);
      in.mark(bom.length);
      for (byte b : bom) {
        if ((0xFF & b) != in.read()) {
          in.reset();
          continue charsetLoop;
        }
      }
      return encodings;
    }
    return Charset.defaultCharset();
  }

  private static String readText(File file) throws IOException {
    Closer res = new Closer();
    try {
      InputStream in = res.using(new FileInputStream(file));
      InputStream bin = res.using(new BufferedInputStream(in));
      Reader reader = res.using(new InputStreamReader(bin, getEncoding(bin)));
      StringBuilder out = new StringBuilder();
      for (int ch = reader.read(); ch != -1; ch = reader.read())
        out.append((char) ch);
      return out.toString();
    } finally {
      res.close();
    }
  }

Uso:

  public static void main(String[] args) throws IOException {
    System.out.println(readText(new File("chinese.txt")));
  }

(System.out usa a codificação padrão, então se ele imprime qualquer coisa sensata depende da sua plataforma e configuração .)

Respondeu 20/04/2009 em 11:14
fonte usuário


votos
4

Se você pode confiar que a codificação de caracteres padrão é UTF-8 (ou alguma outra codificação Unicode), você pode usar o seguinte:

    Writer w = new FileWriter("test.txt");
    w.append("上海");
    w.close();

A maneira mais segura é sempre especificar explicitamente a codificação:

    Writer w = new OutputStreamWriter(new FileOutputStream("test.txt"), "UTF-8");
    w.append("上海");
    w.close();

PS Você pode usar quaisquer caracteres Unicode no código-fonte Java, como método e nomes de variáveis, se o parâmetro -encoding para javac está configurado direito. Isso faz com que o código fonte mais legível do que o escapou \uXXXXformulário.

Respondeu 20/04/2009 em 00:34
fonte usuário

votos
3

Tenha muito cuidado com as abordagens propostas. Mesmo especificando a codificação para o arquivo da seguinte forma:

Escritor w = new OutputStreamWriter (new FileOutputStream ( "test.txt"), "UTF-8");

não vai funcionar se você estiver executando em um sistema operacional como o Windows. Mesmo definindo a propriedade sistema para file.encoding para UTF-8 não corrigir o problema. Isso ocorre porque Java não consegue escrever uma marca de ordem de byte (BOM) para o arquivo. Mesmo se você especificar a codificação quando se escreve para um arquivo, abrir o mesmo arquivo em um aplicativo como o Wordpad irá exibir o texto como lixo, porque ele não detectar o BOM. Tentei executar os exemplos aqui no Windows (com uma codificação de plataforma / recipiente de CP1252).

A seguir bug existe para descrever o assunto em Java:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058

A solução para o momento é escrever a ordem de bytes marcar-se a garantir que o arquivo abre corretamente em outras aplicações. Veja isso para obter mais detalhes sobre o BOM:

http://mindprod.com/jgloss/bom.html

e para uma solução mais correta consulte o seguinte link:

http://tripoverit.blogspot.com/2007/04/javas-utf-8-and-unicode-writing-is.html

Respondeu 20/04/2009 em 01:39
fonte usuário

votos
1

Tente isso,

StringBuffer Shanghai_StrBuf=new StringBuffer("\u4E0A\u6D77");
    boolean Append=true;

    Writer out = new BufferedWriter(new OutputStreamWriter(
        new FileOutputStream(FileName,Append), "UTF8"));
    for (int i=0;i<Shanghai_StrBuf.length();i++) out.write(Shanghai_StrBuf.charAt(i));
    out.close();
Respondeu 20/04/2009 em 01:01
fonte usuário

votos
1

Aqui está uma maneira entre muitos. Basicamente, estamos apenas especificando que a conversão ser feito para UTF-8 antes de emitir bytes para o FileOutputStream:

String FileName = "output.txt";

StringBuffer Shanghai_StrBuf=new StringBuffer("\u4E0A\u6D77");
boolean Append=true;

Writer writer = new OutputStreamWriter(new FileOutputStream(FileName,Append), "UTF-8");
writer.write(Shanghai_StrBuf.toString(), 0, Shanghai_StrBuf.length());
writer.close();

I verificado manualmente esta contra as imagens em http://www.fileformat.info/info/unicode/char/ . No futuro, siga Java padrões de codificação, incluindo nomes de variáveis minúsculas. Além disso, melhora a legibilidade.

Respondeu 20/04/2009 em 00:42
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more