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

时间:2011-05-13 17:58:23

标签: java

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

3 个答案:

答案 0 :(得分:5)

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

我可能错了,但我不认为这就是你在这个问题上所要求的。如果我正确地读你,我想你会问“我怎么读和写任意文件数据?”

这就是我要回答的问题。更新您的问题,如果这不是您正在寻找的。

可以使用DataInputStream和DataOutputStream类轻松实现自定义文件类型。这些将让你阅读&将原语(boolean,char,byte,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标记(类似于以空字符结尾的字符串),你可以避免写长度前缀。

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

所以我可能有一个SuperFancyCodec用于读取/写入整个系统的数据,然后调用我的TinySpecialPurposeCodec。只要流阅读&amp;写作方法是公开的,然后我可以使用面向组件的方法组装新的文件类型。

答案 1 :(得分:3)

扩展通常与解释文件的方式无关。

如果您只想config.dat代替config.xml,则只需重命名该文件即可。 (您通常会为xml-parser提供InputStreamReader作为输入,可以读取任何文件,无论扩展名如何)

如果您所描述的问题是将多个文件(.zip,.jar等)合并到一个.dat文件中,您可以将它们压缩在一起,并命名为扩展名为.dat的zip文件。 Java对zip文件有很好的支持,无论文件名/扩展名如何,都可以处理zip文件。

答案 2 :(得分:1)

在使用Java(或其他任何东西)创建/读取文件时,文件扩展名不会严格依赖于文件数据的实际结构。如果我想,我可以创建一个XML文件file.gweebz。操作系统和应用程序不知道如何处理它,但一旦打开,很明显它是XML。

话虽这么说,遵循已经建立的约定通常是好的,通常.dat文件是二进制格式的文件。您可以根据需要使用.dat,但要注意某些用户可能具有文件类型的操作系统绑定,并且单击您的文件可能会导致其系统上出现与预期不同的行为。

至于如何在Java中完成它。用Java抓取文件句柄很容易......

File myFile = new File("/dir/file.gweebz");

就这么简单,你可以随意命名。您将需要其他类来编写和读取文件或进行压缩,但我会假设您知道如何执行此操作。如果没有,这个网站将有答案。