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

Run*_*ror 5 java eclipse windows jar utf-8

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

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

????????????????????????????????????????????????????
?                          Universidade2010 (18/18)?
?                                         hidden: 0?
????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

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

????????????????????????????????????????????????????
?                          Universidade2010 (19/19)?
?                                         hidden: 0?
????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

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

Writer w = new OutputStreamWriter(fos, "UTF-8");
Run Code Online (Sandbox Code Playgroud)

并将BOM标题写入文件,就像已经回答的问题一样,但在导出到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();
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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';   /* ? */
Run Code Online (Sandbox Code Playgroud)

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

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

McD*_*ell 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();
    }
  }
Run Code Online (Sandbox Code Playgroud)

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

┌──┐
├──┤

像记事本这样的Windows应用程序可以从BOM推断编码并正确解码文件.

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

我错过了一些属性或命令行命令,因此Java知道我想默认创建UTF-8文件吗?

不 - 没有这样的设置.有些人可能会建议file.encoding在命令行上设置,但这是一个坏主意.


我在这里写了一篇关于这个主题的更全面的博客文章.


这是对代码的重新修改:

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(); }
}
Run Code Online (Sandbox Code Playgroud)

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