Java 使用 FileWriter 进行 UTF-8 编码

Java UTF-8 Encoding with FileWriter

我目前正在 java 使用随机世界生成游戏,在游戏开始时我希望它存储图块 ID、X 位置和 Y 位置,以便当我重新-加载游戏它将能够再次生成它。

当我写我的文件时一切正常,但我有一个问题,文件的输出是一个奇怪的字符组合。

代码:

import java.io.*;

public class FileWrite {    
    public static FileWriter writeFile;
    public static BufferedWriter write;

    public static void recordItem(int blockID, int blockX, int blockY, String filePath, String fileName) throws Exception {
        writeFile = new FileWriter("res/save/" + filePath+ fileName, true);
        write = new BufferedWriter(writeFile);

        write.write(blockID);
        write.write(blockX);
        write.write(blockY);
        write.newLine();
        write.flush();
    }
}

文件中的输出:

 @ 
 ` 
 ? 
   
 ? 
 ? 
 ? 
 ? 
 ? 
 ? 
 ? 
 ? 

如何将我的 FileWriter 编码为 UTF-8 以便它显示数字?谢谢您的帮助。 :)

write 方法写入单个字符,因此您使用 Unicode 代码点 blockID、blockX、blockY 写入字符,这不是您想要的。

你的 Writer 是否被编码为 UTF-8 在这里并不那么重要,尽管如果你希望你的文件可以跨机器移植,那么明确编码总是好的,所以尝试 new OutputStreamWriter(new FileOutputStream("res/save/" + filePath+ fileName, true), "UTF-8"); 而不是直接创建一个 FileWriter。直接创建它不允许您指定编码。

而是做这样的事情:

writer.write(String.format("%d %d %d\n", blockID, blockX, blockY));

这会将您的三个数字格式化为一行中的一个字符串,然后再将其发送到文件。

请注意,您不应该在每次要写一行时都创建一个新的 Writer/BufferedWriter。您应该将它们保存在 class 字段中并重复使用同一个编写器。您还需要在完成后关闭该文件,因为操作系统对您同时打开的文件数量有限制,您将 运行 快速关闭该数量当前代码。

只是一个建议,如果您想使持久信息的形式更健壮一些,您可以考虑对象序列化。这比听起来容易。只需要一个实现 Serializable 的静态内部 class,就像这样:

static class JunkRec implements Serializable
{
    private static final long serialVersionUID = 1L;
    final int _blockID, _blockX, _blockY;
    final String _filePath, _fileName;
    public JunkRec(int blockID, int blockX, int blockY, 
                    String filePath, String fileName) 
   {
        _blockID = blockID;
        _blockX = blockX;
        _blockY = blockY;
        _filePath = filePath;
        _fileName = fileName;
    }
    @Override
    public String toString() {
        return String.format("id=%08d x=%04d y=%04d fp=%s fn=%s", 
                _blockID, _blockX, _blockY, _filePath, _fileName);
    }
}

现在,一种存储垃圾记录的方法...

public static void storeJunk(JunkRec jr)
{
    try (
        FileOutputStream fos = new FileOutputStream(
                jr._filePath + jr._fileName + ".ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);) {
        oos.writeObject(jr);
    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
}

另一种恢复 JunkRec 的方法,给定文件名。

public static JunkRec retrieveJunk(String filePath, String fileName)
{
    try (
        FileInputStream fis = new FileInputStream(
                filePath + fileName + ".ser");
        ObjectInputStream ois = new ObjectInputStream(fis);) {
        return (JunkRec) ois.readObject();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
    return null;
}

最后是 main() 中的一个小测试驱动程序...

public static void main(String[] args)
{
    // generate and restore 10 records
    Random r = new Random();
    List<String> names = new ArrayList<>();
    /* do a few in two ways */
    for (int i = 0; i < 5; ++i) {
        int blk = r.nextInt(10000);
        String fname = String.format("BLKID_%02d", i);
        if (names.add(fname)) {
            JunkRec jr = new JunkRec(
                    r.nextInt(10000),
                    r.nextInt(50),
                    r.nextInt(50),
                    "/tmp/",
                    fname);
            storeJunk(jr);
            System.out.println("Wrote: "+jr);
        }
    }

    /* read them all back */
    for (String fname : names) {
        JunkRec jr = retrieveJunk("/tmp/", fname);
        System.out.println("Retrieved: " + jr + " from " + fname);
    }

    /* clean up */
    for (String fname : names) {
        ((File) new File("/tmp/" + fname + ".ser")).delete();
    }
}

这不是生产质量代码,但它显示了序列化是多么容易。有一个陷阱,但一般来说,序列化是基于文件的持久性的可靠解决方案。

只是一个建议。 玩得开心!