ZIP files are archives that store one or more files in (usually) compressed format. Java 1.1 can handle both GZIP and ZIP format. (See RFC 1950, RFC 1951, and RFC 1952, for example, at http://www.faqs.org/rfcs.) In this section we concentrate on the more familiar (but somewhat more complicated) ZIP format and leave the GZIP classes to you if you need them. (They work in much the same way.) NOTE
Each ZIP file has a header with information such as the name of the file and the compression method that was used. In Java, you use a ZipInputStream to read a ZIP file by layering the ZipInputStream constructor onto a FileInputStream. You then need to look at the individual entries in the archive. The getNextEntry method returns an object of type ZipEntry that describes the entry. The read method of the ZipInputStream is modified to return 1 at the end of the current entry (instead of just at the end of the ZIP file). You must then call closeEntry to read the next entry. Here is a typical code sequence to read through a ZIP file:
To read the contents of a ZIP entry, you will probably not want to use the raw read method; usually, you will use the methods of a more competent stream filter. For example, to read a text file inside a ZIP file, you can use the following loop:
The program in Example 12-1 lets you open a ZIP file. It then displays the files stored in the ZIP archive in the combo box at the bottom of the screen. If you double-click on one of the files, the contents of the file are displayed in the text area, as shown in Figure 12-5. Example 12-1. ZipTest.java1. import java.awt.*; 2. import java.awt.event.*; 3. import java.io.*; 4. import java.util.*; 5. import java.util.zip.*; 6. import javax.swing.*; 7. import javax.swing.filechooser.FileFilter; 8. 9. public class ZipTest 10. { 11. public static void main(String[] args) 12. { 13. ZipTestFrame frame = new ZipTestFrame(); 14. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 15. frame.setVisible(true); 16. } 17. } 18. 19. /** 20. A frame with a text area to show the contents of a file inside 21. a zip archive, a combo box to select different files in the 22. archive, and a menu to load a new archive. 23. */ 24. class ZipTestFrame extends JFrame 25. { 26. public ZipTestFrame() 27. { 28. setTitle("ZipTest"); 29. setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 30. 31. // add the menu and the Open and Exit menu items 32. JMenuBar menuBar = new JMenuBar(); 33. JMenu menu = new JMenu("File"); 34. 35. JMenuItem openItem = new JMenuItem("Open"); 36. menu.add(openItem); 37. openItem.addActionListener(new OpenAction()); 38. 39. JMenuItem exitItem = new JMenuItem("Exit"); 40. menu.add(exitItem); 41. exitItem.addActionListener(new 42. ActionListener() 43. { 44. public void actionPerformed(ActionEvent event) 45. { 46. System.exit(0); 47. } 48. }); 49. 50. menuBar.add(menu); 51. setJMenuBar(menuBar); 52. 53. // add the text area and combo box 54. fileText = new JTextArea(); 55. fileCombo = new JComboBox(); 56. fileCombo.addActionListener(new 57. ActionListener() 58. { 59. public void actionPerformed(ActionEvent event) 60. { 61. loadZipFile((String) fileCombo.getSelectedItem()); 62. } 63. }); 64. 65. add(fileCombo, BorderLayout.SOUTH); 66. add(new JScrollPane(fileText), BorderLayout.CENTER); 67. } 68. 69. /** 70. This is the listener for the File->Open menu item. 71. */ 72. private class OpenAction implements ActionListener 73. { 74. public void actionPerformed(ActionEvent event) 75. { 76. // prompt the user for a zip file 77. JFileChooser chooser = new JFileChooser(); 78. chooser.setCurrentDirectory(new File(".")); 79. ExtensionFileFilter filter = new ExtensionFileFilter(); 80. filter.addExtension(".zip"); 81. filter.addExtension(".jar"); 82. filter.setDescription("ZIP archives"); 83. chooser.setFileFilter(filter); 84. int r = chooser.showOpenDialog(ZipTestFrame.this); 85. if (r == JFileChooser.APPROVE_OPTION) 86. { 87. zipname = chooser.getSelectedFile().getPath(); 88. scanZipFile(); 89. } 90. } 91. } 92. 93. /** 94. Scans the contents of the zip archive and populates 95. the combo box. 96. */ 97. public void scanZipFile() 98. { 99. fileCombo.removeAllItems(); 100. try 101. { 102. ZipInputStream zin = new ZipInputStream(new FileInputStream(zipname)); 103. ZipEntry entry; 104. while ((entry = zin.getNextEntry()) != null) 105. { 106. fileCombo.addItem(entry.getName()); 107. zin.closeEntry(); 108. } 109. zin.close(); 110. } 111. catch (IOException e) 112. { 113. e.printStackTrace(); 114. } 115. } 116. 117. /** 118. Loads a file from the zip archive into the text area 119. @param name the name of the file in the archive 120. */ 121. public void loadZipFile(String name) 122. { 123. try 124. { 125. ZipInputStream zin = new ZipInputStream(new FileInputStream(zipname)); 126. ZipEntry entry; 127. fileText.setText(""); 128. 129. // find entry with matching name in archive 130. while ((entry = zin.getNextEntry()) != null) 131. { 132. if (entry.getName().equals(name)) 133. { 134. // read entry into text area 135. BufferedReader in = new BufferedReader(new InputStreamReader(zin)); 136. String line; 137. while ((line = in.readLine()) != null) 138. { 139. fileText.append(line); 140. fileText.append("\n"); 141. } 142. } 143. zin.closeEntry(); 144. } 145. zin.close(); 146. } 147. catch (IOException e) 148. { 149. e.printStackTrace(); 150. } 151. } 152. 153. public static final int DEFAULT_WIDTH = 400; 154. public static final int DEFAULT_HEIGHT = 300; 155. 156. private JComboBox fileCombo; 157. private JTextArea fileText; 158. private String zipname; 159. } 160. 161. /** 162. This file filter matches all files with a given set of 163. extensions. From FileChooserTest in chapter 9 164. */ 165.class ExtensionFileFilter extends FileFilter 166. { 167. /** 168. Adds an extension that this file filter recognizes. 169. @param extension a file extension (such as ".txt" or "txt") 170. */ 171. public void addExtension(String extension) 172. { 173. if (!extension.startsWith(".")) 174. extension = "." + extension; 175. extensions.add(extension.toLowerCase()); 176. } 177. 178. /** 179. Sets a description for the file set that this file filter 180. recognizes. 181. @param aDescription a description for the file set 182. */ 183. public void setDescription(String aDescription) 184. { 185. description = aDescription; 186. } 187. 188. /** 189. Returns a description for the file set that this file 190. filter recognizes. 191. @return a description for the file set 192. */ 193. public String getDescription() 194. { 195. return description; 196. } 197. 198. public boolean accept(File f) 199. { 200. if (f.isDirectory()) return true; 201. String name = f.getName().toLowerCase(); 202. 203. // check if the file name ends with any of the extensions 204. for (String e : extensions) 205. if (name.endsWith(e)) 206. return true; 207. return false; 208. } 209. 210. private String description = ""; 211. private ArrayList<String> extensions = new ArrayList<String>(); 212.} Figure 12-5. The ZipTest programNOTE
To write a ZIP file, you open a ZipOutputStream by layering it onto a FileOutputStream. For each entry that you want to place into the ZIP file, you create a ZipEntry object. You pass the file name to the ZipEntry constructor; it sets the other parameters such as file date and decompression method automatically. You can override these settings if you like. Then, you call the putNextEntry method of the ZipOutputStream to begin writing a new file. Send the file data to the ZIP stream. When you are done, call closeEntry. Repeat for all the files you want to store. Here is a code skeleton:
NOTE
ZIP streams are a good example of the power of the stream abstraction. Both the source and the destination of the ZIP data are completely flexible. You layer the most convenient reader stream onto the ZIP file stream to read the data that are stored in compressed form, and that reader doesn't even realize that the data are being decompressed as they are being requested. And the source of the bytes in ZIP formats need not be a file the ZIP data can come from a network connection. In fact, the JAR files that we discussed in Chapter 10 are ZIP-formatted files. Whenever the class loader of an applet reads a JAR file, it reads and decompresses data from the network. NOTE
java.util.zip.ZipInputStream 1.1
java.util.zip.ZipOutputStream 1.1
java.util.zip.ZipEntry 1.1
java.util.zip.ZipFile 1.1
|