View Javadoc

1   /*
2    *  Copyright (C) 2003-2005 SINTEF
3    *  Author:  Fredrik Vraalsen (fredrik dot vraalsen at sintef dot no)
4    *  Webpage: http://coras.sourceforge.net/
5    *
6    *  This program is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public License
8    *  as published by the Free Software Foundation; either version 2.1
9    *  of the License, or (at your option) any later version.
10   *
11   *  This program is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this program; if not, write to the Free
18   *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19   *  02111-1307 USA
20   */
21  package no.sintef.file;
22  
23  import java.awt.Component;
24  import java.io.BufferedInputStream;
25  import java.io.BufferedOutputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.File;
28  import java.io.FileInputStream;
29  import java.io.FileNotFoundException;
30  import java.io.FileOutputStream;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.net.URL;
34  import java.util.ArrayList;
35  import java.util.Arrays;
36  import java.util.List;
37  
38  import javax.swing.JFileChooser;
39  import javax.swing.JOptionPane;
40  import javax.swing.filechooser.FileFilter;
41  
42  import org.apache.log4j.Logger;
43  
44  /***
45   * IO utility class.
46   * 
47   * @author Fredrik Vraalsen
48   */
49  public final class IOUtils {
50  
51  	private static final Logger LOGGER = Logger.getLogger(IOUtils.class);
52  	private static final int BUF_LEN = 4096;
53  	private static final int IO_WAIT_LENGTH = 100;
54  	private static File currentDir = null;
55  	
56  	/***
57  	 * Prevent instantiation of utility class.
58  	 */
59  	private IOUtils() {
60  	}
61  
62  	/***
63  	 * Get current default directory.
64  	 * 
65  	 * @return current default directory
66  	 */
67  	public static File getDefaultDir() {
68  		return currentDir;
69  	}
70  	
71  	/***
72  	 * Set current default directory.
73  	 * 
74  	 * @param dir new current default directory.
75  	 */
76  	public static void setDefaultDir(File dir) {
77  		if (dir == null || dir.isDirectory()) {
78  			currentDir = dir;
79  		} else {
80  			throw new IllegalArgumentException("dir " + dir + " is not directory");
81  		}
82  	}
83  	
84  	/***
85  	 * Read complete File contents into byte array.
86  	 * 
87  	 * @param file
88  	 *            File to read from
89  	 * @return byte array of File contents
90  	 * @throws IOException
91  	 *             if IO error occurs
92  	 */
93  	public static byte[] readFully(File file) throws IOException {
94  		if (file == null) {
95  			throw new IllegalArgumentException("File is null");
96  		}
97  		if (!file.exists()) {
98  			throw new FileNotFoundException("File not found: "
99  					+ (file != null ? file.getAbsolutePath() : null));
100 		}
101 		if (!file.isFile() || !file.canRead()) {
102 			throw new IOException("Cannot read file: " + file.getAbsolutePath());
103 		}
104 		byte[] bytes = readFully(new FileInputStream(file));
105 		if ((bytes != null) && (bytes.length != file.length())) {
106 		    throw new IOException("Premature end of file: " + file.getAbsolutePath());
107 		}
108 		return bytes;
109 	}
110 
111 	/***
112 	 * Read contents of URL into byte array.
113 	 * 
114 	 * @param url
115 	 *            URL to read from
116 	 * @return byte array of URL contents
117 	 * @throws IOException
118 	 *             if IO error occurs
119 	 */
120 	public static byte[] readFully(URL url) throws IOException {
121 		if (url == null) {
122 			throw new IllegalArgumentException("URL is null");
123 		}
124 		return readFully(url.openStream());
125 	}
126 	
127 	/***
128 	 * Read contents of InputStream into byte array.
129 	 * 
130 	 * @param is
131 	 *            InputStream to read from
132 	 * @return byte array of InputStream contents
133 	 * @throws IOException
134 	 *             if IO error occurs
135 	 */
136 	public static byte[] readFully(InputStream is) throws IOException {
137 	    ByteArrayOutputStream baos = new ByteArrayOutputStream();
138 	    byte[] buf = new byte[BUF_LEN];
139 	    BufferedInputStream bis = new BufferedInputStream(is);
140 	    int read;
141 	    while ((read = bis.read(buf)) != -1) {
142 	        baos.write(buf, 0, read);
143 	        if (read == 0) {
144 	            LOGGER.debug("Waiting for data...");
145 	            try {
146 	            	// TODO Wait for available data? How many times?
147                     Thread.sleep(IO_WAIT_LENGTH); 
148                 } catch (InterruptedException e) {
149                     throw new IOException("Interrupted while waiting for data");
150                 }
151 	        } 
152 	    }
153 	    return baos.toByteArray();
154 	}
155 
156 	/***
157 	 * Save contents of byte array to the specified file.
158 	 * 
159 	 * @param bytes
160 	 *            byte array with contents to save
161 	 * @param file
162 	 *            file to save to
163 	 * @throws IOException
164 	 *             if IO error occurs
165 	 */
166 	public static void saveFile(byte[] bytes, File file) throws IOException {
167 		if (bytes == null || file == null) {
168 			throw new IllegalArgumentException("null argument");
169 		}
170 		if (file.exists() && !file.canWrite()) {
171 			throw new IOException("Unable to write to file: " + file.getAbsolutePath());
172 		}
173 		BufferedOutputStream bos = null;
174 		try {
175 			bos = new BufferedOutputStream(new FileOutputStream(file));
176 			bos.write(bytes);
177 		} finally {
178 			if (bos != null) {
179 			    bos.close();
180 			}
181 		}
182 	}
183 
184 	/***
185 	 * Show file dialog requesting user to choose file to save to.
186 	 * 
187 	 * @param defaultFilename
188 	 *            default file name for dialog
189 	 * @param parent
190 	 *            parent Component to align the dialog to
191 	 * @return File to save contents to, or null if cancelled or file not
192 	 *         writable
193 	 */
194 	public static File showSaveDialog(String defaultFilename, Component parent) {
195 	    while (true) {
196 	        File result =  showFileDialog(defaultFilename, null, parent, JFileChooser.SAVE_DIALOG);
197 	        if (result == null) {
198 	            return null;
199 	        }
200 	        if (!result.exists()) {
201 	            return result;
202 	        }
203 	        if (!result.canWrite()) {
204 	            JOptionPane.showMessageDialog(parent, 
205 	            		"File already exists and is not writeable", 
206 	            		"Save error", JOptionPane.ERROR_MESSAGE);
207 	            // TODO and ask user again...
208 	        } else {
209 	            int option = JOptionPane.showConfirmDialog(parent, 
210 	            		"Overwrite existing file " + result.getName() + "?", 
211 	            		"Overwrite file?", JOptionPane.YES_NO_CANCEL_OPTION);
212 	            if (option == JOptionPane.YES_OPTION) {
213 	                return result;
214 	            } else if (option == JOptionPane.CANCEL_OPTION) {
215 	                return null;
216 	            } // TODO else ask user again...
217 	        }
218 	    }
219 	}
220 	
221 	/***
222 	 * Show file dialog to ask user to select a file to open.
223 	 * 
224 	 * @param defaultFilename
225 	 *            default file name for dialog
226 	 * @param filters
227 	 *            array of filename filters
228 	 * @param parent
229 	 *            parent Component to align the dialog to
230 	 * @return File to open
231 	 */
232 	public static File showOpenDialog(String defaultFilename, FileFilter[] filters, Component parent) {
233 		return showFileDialog(defaultFilename, filters, parent, JFileChooser.OPEN_DIALOG);
234 	}
235 	
236 	/***
237 	 * Merge two FileFilter arrays.
238 	 * 
239 	 * @param f1 the first FileFilter array
240 	 * @param f2 the second FileFilter array
241 	 * @return the merged FileFilters
242 	 */
243 	public static FileFilter[] mergeFilters(FileFilter[] f1, FileFilter[] f2) {
244 		List result = new ArrayList();
245 		if (f1 != null) {
246 			result.addAll(Arrays.asList(f1));
247 		}
248 		if (f2 != null) {
249 			result.addAll(Arrays.asList(f2));
250 		}
251 		return (FileFilter[]) result.toArray(new FileFilter[0]);
252 	}
253 
254 	/***
255 	 * Show file dialog to ask user to select a file to open or save.
256 	 * 
257 	 * @param defaultFilename
258 	 *            default file name for dialog
259 	 * @param filters
260 	 *            array of filename filters
261 	 * @param parent
262 	 *            parent Component to align the dialog to
263 	 * @param type
264 	 *            JFileChooser.OPEN_DIALOG or JFileChooser.SAVE_DIALOG
265 	 * @return File to open or save
266 	 */
267 	private static File showFileDialog(String defaultFilename, FileFilter[] filters, Component parent, int type) {
268 		JFileChooser fileChooser = new JFileChooser();
269 		fileChooser.setDialogType(type);
270 		if (defaultFilename != null) {
271 			fileChooser.setSelectedFile(new File(currentDir, defaultFilename));
272 		} else {
273 			fileChooser.setCurrentDirectory(currentDir);
274 		}
275 		if (filters != null) {
276 		    for (int i = 0; i < filters.length; i++) {
277                 fileChooser.addChoosableFileFilter(filters[i]);
278             }
279 		}
280 		int result;
281 		if (type == JFileChooser.SAVE_DIALOG) {
282 			result = fileChooser.showSaveDialog(parent);
283 		} else {
284 			result = fileChooser.showOpenDialog(parent);
285 		}
286 		if (result == JFileChooser.CANCEL_OPTION || result == JFileChooser.ERROR_OPTION) {
287 			return null;
288 		} else {
289 			currentDir = fileChooser.getCurrentDirectory();
290 			File f = fileChooser.getSelectedFile();
291 			if (f.isDirectory()) {
292 				f = new File(f, defaultFilename);
293 			}
294 			return f;
295 		}
296 	}
297 	
298 }