java - 在 Java 中创建和读取自定义文件类型

标签 java

我正在创建一个安装程序,并且有一些在安装过程中必须读取的资源文件(.xml、.zip 文件、.jar 文件等),但我想将它们打包到自定义文件中(即 .dat 文件),这样在分发时,用户就不会过多地摆弄它们。问题是安装程序必须用 Java 编写,而我以前从未用任何编程语言做过此类事情。有可能吗?如果是这样,我如何以一种可以被我的 Java 应用程序读取的方式打包它,以及如何让我的 Java 应用程序读取它?

最佳答案

关于此文件类型的要求,您需要自己回答很多问题。是否需要压缩?加密的?是否需要支持随机读取,或者流读取是否足够好?

我可能是错的,但我不认为这就是你在这个问题中要问的。如果我没理解错的话,我想你是在问“如何读取和写入任意文件数据?”

这就是我要回答的问题。如果这不完全是您想要的,请更新您的问题。

使用 DataInputStream 和 DataOutputStream 类可以轻松实现自定义文件类型。这些将允许您在流中读取和写入基元( boolean 、字符、字节、int、long、float、double)。还有一些读取和写入 UTF-8 编码字符串、字节数组和其他一些好东西的便捷方法。

让我们开始吧。

为了便于论证,我们假设所有数据元素都是字节数组。他们每个人都有一个名字。所以我的文件类型可以在逻辑上建模为 Map<String, byte[]> 。我将像这样实现我的自定义文件类型读取器/写入器类:

public class MyFileTypeCodec {

   public static void writeToFile(File f, Map<String, byte[]> map)
      throws IOException {

      // Create an output stream
      DataOutputStream stream = new DataOutputStream(
         new BufferedOutputStream(new FileOutputStream(f))
      );

      // Delegate writing to the stream to a separate method
      writeToStream(stream, map);

      // Always be sure to flush & close the stream.
      stream.flush();
      stream.close();
   }

   public static Map<String, byte[]> readFromFile(File f)
      throws IOException {

      // Create an input stream
      DataInputStream stream = new DataInputStream(
         new BufferedInputStream(new FileInputStream(f))
      );

      // Delegate reading from the stream to a separate method
      Map<String, byte[]> map = readFromStream(stream);

      // Always be sure to close the stream.
      stream.close();

      return map;
}

   public static void writeToStream(DataOutputStream stream, Map<String, byte[]> map)
      throws IOException {

      // First, write the number of entries in the map.
      stream.writeInt(map.size());

      // Next, iterate through all the entries in the map
      for (Map.Entry<String, byte[]> entry : map.entrySet()) {

         // Write the name of this piece of data.
         stream.writeUTF(entry.getKey());

         // Write the data represented by this name, making sure to
         // prefix the data with an integer representing its length.
         byte[] data = entry.getValue();
         stream.writeInt(data.length);
         stream.write(data);
      }

   }

   public static Map<String, byte[]> readFromStream(DataInputStream stream)
      throws IOException {

      // Create the data structure to contain the data from my custom file
      Map<String, byte[]> map = new HashMap<String, byte[]>();

      // Read the number of entries in this file
      int entryCount = stream.readInt();

      // Iterate through all the entries in the file, and add them to the map
      for (int i = 0; i < entryCount; i++) {

         // Read the name of this entry
         String name = stream.readUTF();

         // Read the data associated with this name, remembering that the
         // data has an integer prefix representing the array length.
         int dataLength = stream.readInt();
         byte[] data = new byte[dataLength];
         stream.read(data, 0, dataLength);

         // Add this entry to the map
         map.put(name, data);
      }

      return map;

   }

}

基本思想是,如果您可以将任何数据表示为基元的某种组合,则可以将任何数据写入输出流(并再次读回)。数组(或其他集合)可以用它们的长度作为前缀,就像我在这里所做的那样。或者,如果您在末尾放置 TERMINUS 标记(类似于以 null 结尾的字符串),则可以避免编写长度前缀。

当我实现自定义文件类型编解码器时,我总是使用这种设置,将文件 IO 方法委托(delegate)给流 IO 方法。通常,我后来发现我从这个流中读取和写入的对象可以很容易地写入一些更大和更复杂的文件中。

所以我可能有一个SuperFancyCodec用于读取/写入整个系统的数据,它向下调用我的 TinySpecialPurposeCodec 。只要流读写方法是公共(public)的,那么我就可以使用面向组件的方法组装新的文件类型。

关于java - 在 Java 中创建和读取自定义文件类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5995899/

相关文章:

java - 累积递归

Java 8 嵌套 null 检查列表中映射中的字符串

java - jsp中 "<%=TITLE %> "和 "${TITLE} "有什么不同?

java - xsl中如何找出空字符串值的元素节点

c# - 是什么使模板与通用模板不同?

java - 在java中将数组元素向左移动三位

java - maven 自定义程序集 - 如何复制外部引用文件夹

java - 无法从 JSON 转换;意外字符 ('f'(代码 102)): Expected space separating root-level values at (String )"5f19a7e99933db43cb23e83d"

JavaFX FXML 标签不更新其值

java - 使用java进行多线程交叉验证