从可运行的Jar创建Java中的UTF-8文件

时间:2010-06-13 16:56:08

标签: java windows eclipse utf-8 jar

我有一个Java项目,我将类文件的属性设置为UTF-8(我使用了默认CP1252上找不到的很多外来字符)。

目标是创建一个包含项目列表的文本文件(在Windows中)。 从Eclipse本身运行类文件时(按Ctrl + F11),它可以完美地创建文件并在另一个编辑器中打开它(我正在使用Notepad ++)我可以看到我想要的字符。

┌──────────────────────────────────────────────────┐
│                          Universidade2010 (18/18)│
│                                         hidden: 0│
├──────────────────────────────────────────────────┤

但是,当我将项目(使用Eclipse)导出为可运行的Jar并使用'javaw -jar project.jar'运行时,创建的新文件是一堆问号

????????????????????????????????????????????????????
?                          Universidade2010 (19/19)?
?                                         hidden: 0?
????????????????????????????????????????????????????

我已经遵循了一些关于如何使用UTF-8(在Java上默认情况下似乎已经打破)的提示,试图纠正这个问题,所以现在我正在使用

Writer w = new OutputStreamWriter(fos, "UTF-8");

并将BOM标头写入文件,如此question already answered,但导出到Jar时仍然没有运气

我是否遗漏了一些属性或命令行命令,因此Java知道我想默认创建UTF-8文件?


问题不在于创建文件本身,因为在开发文件时正确输出(使用unicode字符)

创建文件的类现在(并遵循使用Charset类的建议),如下所示:

public class Printer {

    File f;
    FileOutputStream fos;
    Writer w;
    final byte[] utf8_bom = { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };

    public Printer(String filename){
        f = new File(filename);
        try {
            fos = new FileOutputStream(f);
            w = new OutputStreamWriter(fos, Charset.forName("UTF-8"));
            fos.write(utf8_bom);
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void print(String s) {
        if(fos != null){
            try {
                fos.write(s.getBytes());
                fos.flush();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

所有使用的字符都是这样定义的:

private final char pipe = '\u2502';         /* │ */
private final char line = '\u2500';         /* ─ */
private final char pipeleft = '\u251c';     /* ├ */
private final char piperight = '\u2524';    /* ┤ */
private final char cupleft = '\u250c';      /* ┌ */
private final char cupright = '\u2510';     /* ┐ */
private final char cdownleft = '\u2514';    /* └ */
private final char cdownright = '\u2518';   /* ┘ */

问题依然存在,当简单地通过在Eclipse上运行项目输出到文件时,文件就完美了,但是在将项目部署到Jar并运行它之后,输出的文件的格式被破坏了(我发现了他们被'?'char)取代

我认为这不是代码的问题,将其部署到Jar文件是一个问题,我认为Eclipse正在将源文件编译为CP1252或其他东西,但是甚至用它们替换所有unicode字符代码常量没有帮助

1 个答案:

答案 0 :(得分:6)

  

我已经遵循了一些关于如何使用UTF-8的提示(默认情况下在Java上似乎已被打破)

由于历史原因,Java的编码默认为系统编码(在Windows 95上更有意义)。这种行为不太可能改变。据我所知,Java的编码器实现没有任何破坏。

  private static final String BOM = "\ufeff";

  public static void main(String[] args) throws IOException {
    String data = "\u250c\u2500\u2500\u2510\r\n\u251c\u2500\u2500\u2524";
    OutputStream out = new FileOutputStream("data.txt");
    Closeable resource = out;
    try {
      Writer writer = new OutputStreamWriter(out, Charset.forName("UTF-8"));
      resource = writer;
      writer.write(BOM);
      writer.write(data);
    } finally {
      resource.close();
    }
  }

上面的代码将发出以下带有字节顺序标记的文本:

┌──┐
├──┤

记事本等Windows应用可以从BOM中推断出编码并正确解码文件。

没有代码,就无法发现任何错误。

  

我是否遗漏了一些属性或命令行命令,因此Java知道我想默认创建UTF-8文件?

不 - 没有这样的设置。有些人可能会建议在命令行上设置file.encoding,但这是bad idea


我写了一篇关于这个主题here的更全面的博文。


这是your code

的改编
public class Printer implements Closeable {
  private PrintWriter pw;
  private boolean error;

  public Printer(String name) {
    try {
      pw = new PrintWriter(name, "UTF-8");
      pw.print('\uFEFF'); // BOM
      error = false;
    } catch (IOException e) {
      error = true;
    }
  }

  public void print(String s) {
    if (pw == null) return;
    pw.print(s);
    pw.flush();
  }

  public boolean checkError() { return error || pw.checkError(); }

  @Override public void close() { if (pw != null) pw.close(); }
}

您想要的大部分功能已存在于PrintWriter中。请注意,您应该提供一些机制来检查基础错误并关闭流(或者您有泄漏文件句柄的风险)。