10

我使用下面的代码将汉字保存到一个.txt文件中,但是当我用写字板打开它时,我无法阅读它。

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

我能做些什么 ?我知道如果我将汉字剪切并粘贴到写字板中,我可以将其保存为 .txt 文件。我如何在 Java 中做到这一点?

4

5 回答 5

10

这里有几个因素在起作用:

  • 文本文件没有用于描述其编码的内在元数据(关于尖括号税的所有讨论,XML 流行是有原因的)
  • Windows 的默认编码仍然是 8 位(或双字节)“ ANSI ”字符集,值范围有限 - 以这种格式编写的文本文件不可移植
  • 为了从 ANSI 文件中区分 Unicode 文件,Windows 应用程序依赖于文件开头是否存在字节顺序标记严格来说并非如此 - Raymond Chen 解释道)。从理论上讲,BOM 可以告诉您数据的字节顺序(字节顺序)。对于 UTF-8,即使只有一个字节顺序,Windows 应用程序也依赖标记字节来自动确定它是 Unicode(尽管您会注意到记事本在其打开/保存对话框中有一个编码选项)。
  • 说 Java 坏了是错误的,因为它不会自动编写 UTF-8 BOM。例如,在 Unix 系统上,将 BOM 写入脚本文件是错误的,并且许多 Unix 系统使用 UTF-8 作为其默认编码。有时您也不希望在 Windows 上使用它,例如将数据附加到现有文件时:fos = new FileOutputStream(FileName,Append);

这是一种可靠地将 UTF-8 数据附加到文件的方法:

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

用法:

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

注意:如果文件已经存在并且您选择附加并且现有数据不是UTF-8 编码的,那么代码将创建的唯一东西就是一团糟。

这是Closer此代码中使用的类型:

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

此代码对如何根据字节顺序标记读取文件进行了 Windows 风格的最佳猜测:

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

用法:

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

(System.out 使用默认编码,因此它是否打印任何合理的内容取决于您的平台和配置。)

于 2009-04-20T10:14:02.207 回答
4

如果您可以相信默认字符编码是 UTF-8(或其他一些 Unicode 编码),则可以使用以下内容:

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

最安全的方法是始终明确指定编码:

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

PS 如果 javac 的 -encoding 参数配置正确,您可以在 Java 源代码中使用任何 Unicode 字符,甚至作为方法和变量名称。这使得源代码比转义\uXXXX形式更具可读性。

于 2009-04-19T23:34:02.150 回答
3

对建议的方法要非常小心。甚至指定文件的编码如下:

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

如果您在 Windows 等操作系统下运行,则无法正常工作。即使将 file.encoding 的系统属性设置为 UTF-8 也不能解决问题。这是因为 Java 无法为文件写入字节顺序标记 (BOM)。即使您在写入文件时指定了编码,在写字板等应用程序中打开同一个文件也会将文本显示为垃圾,因为它不会检测 BOM。我尝试在 Windows 中运行这些示例(使用 CP1252 的平台/容器编码)。

存在以下错误来描述 Java 中的问题:

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

暂时的解决办法是自己写字节序标记,以确保文件在其他应用程序中正确打开。有关 BOM 的更多详细信息,请参见此处:

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

对于更正确的解决方案,请参见以下链接:

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

于 2009-04-20T00:39:19.530 回答
1

这是众多方法中的一种。基本上,我们只是指定在将字节输出到 FileOutputStream 之前完成到 UTF-8 的转换:

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

我针对http://www.fileformat.info/info/unicode/char/上的图像手动验证了这一点。将来,请遵循 Java 编码标准,包括小写变量名。它提高了可读性。

于 2009-04-19T23:42:24.097 回答
1

试试这个,

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();
于 2009-04-20T00:01:20.213 回答