001: /*
002: * FileUtil.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.util;
013:
014: import java.io.BufferedReader;
015: import java.io.Closeable;
016: import java.io.File;
017: import java.io.FileReader;
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.io.OutputStream;
021: import java.io.Reader;
022: import java.util.Collection;
023: import java.util.HashSet;
024: import java.util.List;
025: import java.util.Set;
026: import workbench.log.LogMgr;
027:
028: /**
029: * @author support@sql-workbench.net
030: */
031: public class FileUtil {
032: private static final int BUFF_SIZE = 16 * 1024;
033:
034: /*
035: * Closes all streams in the list.
036: * @param a list of streams to close
037: * @see #closeQuitely(Closeable)
038: */
039: public static void closeStreams(List<Closeable> streams) {
040: if (streams == null)
041: return;
042:
043: for (Closeable str : streams) {
044: closeQuitely(str);
045: }
046: }
047:
048: /**
049: * Read the lines of the given Reader into a Collection.
050: * The Reader will be closed after all lines have been read.
051: *
052: * @param in the "file" to read
053: * @return a Collection with all the lines in the file
054: */
055: public static Collection<String> getLines(BufferedReader in) {
056: Set result = new HashSet<String>();
057:
058: try {
059: String line;
060: while ((line = in.readLine()) != null) {
061: if (!StringUtil.isEmptyString(line))
062: result.add(line);
063: }
064: } catch (Exception e) {
065: LogMgr.logError("FileUtil.getLines", "Error reading lines",
066: e);
067: } finally {
068: closeQuitely(in);
069: }
070: return result;
071: }
072:
073: /**
074: * Read the contents of the Reader into the provided StringBuilder.
075: * Max. numLines lines are read.
076: *
077: * The Reader will not be closed
078: *
079: * @param in the Reader to be used
080: * @param buffer the StringBuilder to received the lines
081: * @param numLines the max. number of lines to be read
082: * @param lineEnd the lineEnding to be used
083: * @return the number of lines read
084: */
085: public static final int readLines(BufferedReader in,
086: StringBuilder buffer, int numLines, String lineEnd)
087: throws IOException {
088: int lines = 0;
089: String line = in.readLine();
090: while (line != null && lines < numLines) {
091: buffer.append(line);
092: buffer.append(lineEnd);
093: lines++;
094: line = in.readLine();
095: }
096: if (line != null) {
097: // loop was ended due to numLines reached, so append the
098: // last line retrieved
099: buffer.append(line);
100: buffer.append(lineEnd);
101: }
102: return lines;
103: }
104:
105: /**
106: * Try to detect the line ending used by the passed Reader.
107: * This will advance the reader until a line ending is found.
108: * The reader will not be closed
109: *
110: * @param in the "file" to test
111: * @return the sequence of characters used as the line ending (e.g. \n or \r\n)
112: * @throws java.io.IOException
113: */
114: public static final String getLineEnding(Reader in)
115: throws IOException {
116: String ending = null;
117: char c = (char) in.read();
118: while (c != -1) {
119: if (c == '\r') {
120: char n = (char) in.read();
121: if (n == '\n') {
122: ending = "\r\n";
123: break;
124: }
125: } else if (c == '\n') {
126: ending = "\n";
127: break;
128: }
129: c = (char) in.read();
130: }
131: return ending;
132: }
133:
134: public static final long estimateRecords(File f) throws IOException {
135: return estimateRecords(f, 5);
136: }
137:
138: /**
139: * Tries to estimate the number of records in the given file.
140: * This is done by reading the first <tt>sampleLines</tt> records
141: * of the file and assuming the average size of an row in the first
142: * lines is close to the average row in the complete file.
143: */
144: public static final long estimateRecords(File f, long sampleLines)
145: throws IOException {
146: if (sampleLines <= 0)
147: throw new IllegalArgumentException(
148: "Sample size must be greater then zero");
149: if (!f.exists())
150: return -1;
151: if (!f.isFile())
152: return -1;
153: long size = f.length();
154: if (size == 0)
155: return 0;
156:
157: long lineSize = 0;
158:
159: BufferedReader in = null;
160: try {
161: in = new BufferedReader(new FileReader(f), 8192);
162: in.readLine(); // skip the first line
163: int lfSize = StringUtil.LINE_TERMINATOR.length();
164: for (int i = 0; i < sampleLines; i++) {
165: String line = in.readLine();
166: if (line == null)
167: return i + 1;
168: lineSize += (line.length() + lfSize);
169: }
170: } finally {
171: closeQuitely(in);
172: }
173: return (size / (lineSize / sampleLines));
174:
175: }
176:
177: /**
178: * Copies the content of the InputStream to the OutputStream.
179: * Both streams are closed automatically.
180: */
181: public static long copy(InputStream in, OutputStream out)
182: throws IOException {
183: long filesize = 0;
184: try {
185: byte[] buffer = new byte[BUFF_SIZE];
186: int bytesRead = in.read(buffer);
187: while (bytesRead != -1) {
188: filesize += bytesRead;
189: out.write(buffer, 0, bytesRead);
190: bytesRead = in.read(buffer);
191: }
192: } finally {
193: closeQuitely(out);
194: closeQuitely(in);
195: }
196: return filesize;
197: }
198:
199: /**
200: * Read the content of the Reader into a String.
201: * The Reader is closed automatically.
202: */
203: public static String readCharacters(Reader in) throws IOException {
204: if (in == null)
205: return null;
206: StringBuilder result = new StringBuilder(1024);
207: char[] buff = new char[BUFF_SIZE];
208: int bytesRead = in.read(buff);
209: try {
210: while (bytesRead > -1) {
211: result.append(buff, 0, bytesRead);
212: bytesRead = in.read(buff);
213: }
214: } finally {
215: closeQuitely(in);
216: }
217: return result.toString();
218: }
219:
220: /**
221: * Read the content of the InputStream into a ByteArray.
222: * The InputStream is closed automatically.
223: */
224: public static byte[] readBytes(InputStream in) throws IOException {
225: if (in == null)
226: return null;
227: ByteBuffer result = new ByteBuffer();
228: byte[] buff = new byte[BUFF_SIZE];
229:
230: try {
231: int bytesRead = in.read(buff);
232: while (bytesRead > -1) {
233: result.append(buff, 0, bytesRead);
234: bytesRead = in.read(buff);
235: }
236: } finally {
237: closeQuitely(in);
238: }
239: return result.getBuffer();
240: }
241:
242: /**
243: * Returns the number of characters according to the
244: * encoding in the specified file. For single-byte
245: * encodings this should be identical to source.length()
246: *
247: * For large files this might take some time!
248: *
249: * @param source the (text) file to check
250: * @param encoding the encoding of the text file
251: * @return the number of characters (not bytes) in the file
252: */
253: public static long getCharacterLength(File source, String encoding)
254: throws IOException {
255: BufferedReader r = null;
256: long result = 0;
257: try {
258: r = EncodingUtil.createBufferedReader(source, encoding,
259: 32 * 1024);
260: // Not very efficient, but I can't think of a different solution
261: // to retrieve the number of characters
262: result = r.skip(Long.MAX_VALUE);
263: } finally {
264: closeQuitely(r);
265: }
266:
267: return result;
268: }
269:
270: /**
271: * Closes a Closeable without throwing any errors
272: *
273: * @param c the Closeable to close
274: */
275: public static void closeQuitely(Closeable c) {
276: if (c == null)
277: return;
278:
279: try {
280: c.close();
281: } catch (IOException e) {
282: // ignore
283: }
284: }
285: }
|