2011-05-13 129 views
2

我正在创建一个安装程序,并且有一些必须在安装期间读取的资源文件(.xmls,.zip文件,.jar文件等) d喜欢将它们打包成一个自定义文件(即.dat文件),以便在分发时,用户不会太多地混淆它们。问题是安装程序必须用Java编写,而且我从来没有在任何编程语言中做过这种事情。它甚至有可能吗?如果是这样,那么我怎样才能将它打包成一种可供我的Java应用程序读取的方式,以及如何让我的Java应用程序读取它?在Java中创建和读取自定义文件类型

回答

3

扩展通常与解释文件的方式很少有关。

如果您只想要config.dat而不是​​3210,那么您只需重命名该文件即可。 (您最好给一个XML解析器InputStreamReader作为输入,它可以读取任何文件,无论扩展名)

如果您所描述的问题的是结合多个文件,文件(.zip ,.jar等)整合到单个.dat文件中,您可以将它们压缩到一起,并以.dat扩展名命名zip文件。 Java对zip文件有很好的支持,并且可以处理zip文件,而不管文件名/扩展名。

+0

“扩展通常与解释文件的方式无关。”我知道的很多。但是关于压缩它们的好的指针,重命名并使用Java API来处理它。我不是Java专家,但我会研究它,谢谢。 – makoshichi 2011-05-13 18:17:14

+0

当然,没问题。 – aioobe 2011-05-13 18:19:19

+0

我已经按照你的初始想法,除了我提取.dat文件的内容到系统临时文件夹,并从那里得到我需要的文件。工作奇迹,谢谢! – makoshichi 2011-05-16 20:33:07

1

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

这就是说,遵循已建立的惯例通常是很好的,通常.dat文件是二进制格式的文件。您可以使用.dat获得您想要的内容,但需要警告某些用户可能具有该文件类型的操作系统绑定并单击您的文件可能会导致系统上的行为与预期不同。

至于如何在Java中做到这一点。在Java中抓取文件句柄很容易...

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

这很简单,你可以任意命名它。您将需要其他类来写入和读取文件或进行压缩,但我会假设您知道如何做到这一点。如果没有,该网站将有答案。

5

有很多问题需要您自己回答有关此文件类型的要求。它需要被压缩吗?加密?它需要支持随机访问阅读,还是流式阅读足够好?

我可能是错的,但我不认为这就是你问这个问题。如果我正确地阅读了你的话,我想你是问“我怎么读&写入任意文件数据?”

这就是我会回答的问题。更新你的问题,如果这不是你想要的。

自定义文件类型可以使用DataInputStream和DataOutputStream类轻松实现。这些将允许您读取&将原语(布尔,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标记(类似于以null结尾的字符串),则可以避免编写长度前缀。

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

因此,我可能有一个SuperFancyCodec用于读取/写入整个系统的数据,它会调用我的TinySpecialPurposeCodec。只要流读&写作方法是公开的,那么我可以使用面向组件的方法来组装新的文件类型。

相关问题