0001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
0002 *
0003 * Copyright 2000-2013, Michael Meyling <mime@qedeq.org>.
0004 *
0005 * "Hilbert II" is free software; you can redistribute
0006 * it and/or modify it under the terms of the GNU General Public
0007 * License as published by the Free Software Foundation; either
0008 * version 2 of the License, or (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0013 * GNU General Public License for more details.
0014 */
0015
0016 package org.qedeq.base.io;
0017
0018 import java.io.BufferedOutputStream;
0019 import java.io.BufferedReader;
0020 import java.io.BufferedWriter;
0021 import java.io.ByteArrayInputStream;
0022 import java.io.File;
0023 import java.io.FileFilter;
0024 import java.io.FileInputStream;
0025 import java.io.FileOutputStream;
0026 import java.io.FileReader;
0027 import java.io.FileWriter;
0028 import java.io.IOException;
0029 import java.io.InputStream;
0030 import java.io.InputStreamReader;
0031 import java.io.OutputStream;
0032 import java.io.OutputStreamWriter;
0033 import java.io.Reader;
0034 import java.io.UnsupportedEncodingException;
0035 import java.io.Writer;
0036 import java.net.URL;
0037 import java.nio.charset.Charset;
0038 import java.util.ArrayList;
0039 import java.util.Arrays;
0040 import java.util.Enumeration;
0041 import java.util.Iterator;
0042 import java.util.List;
0043 import java.util.Map;
0044 import java.util.Properties;
0045 import java.util.StringTokenizer;
0046 import java.util.TreeMap;
0047
0048 import org.apache.commons.lang.SystemUtils;
0049
0050
0051 /**
0052 * A collection of useful static methods for input and output.
0053 *
0054 * LATER mime 20070101: use StringBuilder instead of StringBuffer if working under JDK 1.5
0055 *
0056 * @author Michael Meyling
0057 */
0058 public final class IoUtility {
0059
0060 /**
0061 * Constructor, should never be called.
0062 */
0063 private IoUtility() {
0064 // don't call me
0065 }
0066
0067 /**
0068 * Get default encoding for this system.
0069 *
0070 * @return Default encoding for this system.
0071 */
0072 public static String getDefaultEncoding() {
0073 return SystemUtils.FILE_ENCODING;
0074 // mime 20090630: under ubuntu the following gave the encoding ASCII:
0075 // return new InputStreamReader(
0076 // new ByteArrayInputStream(new byte[0])).getEncoding();
0077 // but it was: file.encoding="ANSI_X3.41968"
0078 }
0079
0080 /**
0081 * Get working Java encoding.
0082 *
0083 * @param encoding Try this encoding.
0084 * @return This is <code>encoding</code> if it is supported. Or an other
0085 * encoding that is supported by this system.
0086 */
0087 public static String getWorkingEncoding(final String encoding) {
0088 if (encoding != null) {
0089 try {
0090 if (Charset.isSupported(encoding)
0091 && Charset.forName(encoding).canEncode()) {
0092 return encoding;
0093 }
0094 } catch (RuntimeException e) {
0095 // ignore
0096 }
0097 }
0098 // we must inform someone, but using
0099 // Trace within this class is not wise, because it is used
0100 // before the Trace is initialized.
0101 System.err.println("not supported encoding: " + encoding);
0102 return "ISO-8859-1"; // every system must support this
0103 }
0104
0105 /**
0106 * Reads a file and returns the contents as a <code>String</code>.
0107 *
0108 * @param filename Name of the file (could include path).
0109 * @param encoding Take this encoding.
0110 * @return Contents of file.
0111 * @throws IOException File exception occurred.
0112 */
0113 public static String loadFile(final String filename, final String encoding)
0114 throws IOException {
0115
0116 final StringBuffer buffer = new StringBuffer();
0117 loadFile(filename, buffer, encoding);
0118 return buffer.toString();
0119 }
0120
0121 /**
0122 * Reads contents of a file into a string buffer.
0123 *
0124 * @param filename Name of the file (could include path).
0125 * @param buffer Buffer to fill with file contents.
0126 * @param encoding Take this encoding.
0127 * @throws IOException File exception occurred.
0128 */
0129 public static void loadFile(final String filename,
0130 final StringBuffer buffer, final String encoding)
0131 throws IOException {
0132 loadFile(new File(filename), buffer, encoding);
0133 }
0134
0135 /**
0136 * Reads contents of a stream into a string buffer. Stream is not closed.
0137 *
0138 * @param in This stream will be loaded.
0139 * @param buffer Buffer to fill with file contents.
0140 * @throws IOException File exception occurred.
0141 *
0142 * @deprecated Use {@link #loadReader(Reader, StringBuffer)}.
0143 */
0144 public static void loadStream(final InputStream in, final StringBuffer buffer)
0145 throws IOException {
0146
0147 buffer.setLength(0);
0148 int c;
0149 while ((c = in.read()) >= 0) {
0150 buffer.append((char) c);
0151 }
0152 }
0153
0154 /**
0155 * Returns contents of a stream into a string, respecting a maximum length.
0156 * No exceptions are thrown. Stream is not closed.
0157 *
0158 * @param in This stream will be loaded.
0159 * @param maxLength This length is not exceeded.
0160 * @return readData Data read, is not <code>null</code>.
0161 */
0162 public static String loadStreamWithoutException(final InputStream in, final int maxLength) {
0163
0164 if (in == null) {
0165 return "";
0166 }
0167 final StringBuffer buffer = new StringBuffer();
0168 buffer.setLength(0);
0169 try {
0170 int counter = 0;
0171 int c;
0172 while (counter++ < maxLength) {
0173 c = in.read();
0174 if (c < 0) {
0175 break;
0176 }
0177 buffer.append((char) c);
0178 }
0179 } catch (IOException e) {
0180 // ignored
0181 } catch (RuntimeException e) {
0182 // ignored
0183 }
0184 return buffer.toString();
0185 }
0186
0187 /**
0188 * Reads contents of a {@link Reader} into a string buffer. Reader is not closed.
0189 *
0190 * @param in This reader will be loaded.
0191 * @param buffer Buffer to fill with file contents.
0192 * @throws IOException File exception occurred.
0193 */
0194 public static void loadReader(final Reader in, final StringBuffer buffer)
0195 throws IOException {
0196
0197 buffer.setLength(0);
0198 int c;
0199 while ((c = in.read()) >= 0) {
0200 buffer.append((char) c);
0201 }
0202 }
0203
0204 /**
0205 * Reads contents of a file into a string buffer. Uses default encoding.
0206 *
0207 * @param file This file will be loaded.
0208 * @param buffer Buffer to fill with file contents.
0209 * @throws IOException File exception occurred.
0210 *
0211 * @deprecated Use {@link #loadFile(File, StringBuffer, String)}.
0212 */
0213 public static void loadFile(final File file,
0214 final StringBuffer buffer)
0215 throws IOException {
0216
0217 final int size = (int) file.length();
0218 final char[] data = new char[size];
0219 buffer.setLength(0);
0220 FileReader in = null;
0221 try {
0222 in = new FileReader(file);
0223 int charsread = 0;
0224 while (charsread < size) {
0225 charsread += in.read(data, charsread, size - charsread);
0226 }
0227 } finally {
0228 close(in);
0229 }
0230 buffer.insert(0, data);
0231 }
0232
0233 /**
0234 * Reads contents of a file into a string buffer.
0235 *
0236 * @param file This file will be loaded.
0237 * @param buffer Buffer to fill with file contents.
0238 * @param encoding Take this encoding.
0239 * @throws IOException File exception occurred.
0240 */
0241 public static void loadFile(final File file,
0242 final StringBuffer buffer, final String encoding)
0243 throws IOException {
0244
0245 buffer.setLength((int) file.length()); // ensure capacity
0246 buffer.setLength(0);
0247 final InputStreamReader in = new InputStreamReader(new FileInputStream(file), encoding);
0248 final char[] data = new char[10 * 1024];
0249
0250 try {
0251 int charsread = 0;
0252 while (0 < (charsread = in.read(data, 0, data.length))) {
0253 buffer.append(data, 0, charsread);
0254 }
0255 } finally {
0256 in.close();
0257 }
0258 }
0259
0260 /**
0261 * Reads a file and returns the contents as a <code>String</code>.
0262 *
0263 * @param file File to load from.
0264 * @return Contents of file.
0265 * @throws IOException File exception occurred.
0266 */
0267 public static final byte[] loadFileBinary(final File file) throws IOException {
0268 final int size = (int) file.length();
0269 final FileInputStream in = new FileInputStream(file);
0270 try {
0271 final byte[] data = new byte[size];
0272 int charsread = 0;
0273 while (charsread < size) {
0274 final int read = in.read(data, charsread, size - charsread);
0275 if (read == -1) {
0276 final byte[] result = new byte[charsread];
0277 System.arraycopy(data, 0, result, 0, charsread);
0278 return result;
0279 }
0280 charsread += read;
0281 }
0282 in.close();
0283 return data;
0284 } finally {
0285 close(in);
0286 }
0287 }
0288
0289
0290 /**
0291 * Reads contents of an URL into a string buffer. The filling is character set dependent.
0292 * Content is added to the end of buffer. (Existing data is not cleared.)
0293 * <p>
0294 * All parameters should not be <code>null</code>.
0295 * @param url This URL will be loaded.
0296 * @param buffer Buffer to fill with file contents.
0297 * @throws IOException Reading failed.
0298 *
0299 * @deprecated Choose correct encoding.
0300 */
0301 public static void loadFile(final URL url, final StringBuffer buffer) throws IOException {
0302 InputStream in = null;
0303 BufferedReader dis = null;
0304 try {
0305 in = url.openStream();
0306 dis = new BufferedReader(new InputStreamReader(in));
0307 int i;
0308 while ((i = dis.read()) != -1) {
0309 buffer.append((char) i);
0310 }
0311 } finally {
0312 close(in);
0313 close(dis);
0314 }
0315 }
0316
0317 /**
0318 * Reads contents of an URL into a StringBuffer. The filling is character set dependent. The
0319 * buffer is not cleared, contents is just added.
0320 * <p>
0321 * All parameters should not be <code>null</code>.
0322 * @param url This URL will be loaded.
0323 * @param buffer Buffer to fill with file contents.
0324 * @param encoding Take this encoding.
0325 * @throws IOException Reading failed.
0326 */
0327 public static void loadFile(final URL url, final StringBuffer buffer, final String encoding)
0328 throws IOException {
0329 InputStream in = null;
0330 BufferedReader dis = null;
0331 try {
0332 in = url.openStream();
0333 dis = new BufferedReader(new InputStreamReader(in, encoding));
0334 int i;
0335 while ((i = dis.read()) != -1) {
0336 buffer.append((char) i);
0337 }
0338 } finally {
0339 close(in);
0340 close(dis);
0341 }
0342 }
0343
0344 /**
0345 * Save binary contents of an URL into a file. Existing files are overwritten.
0346 *
0347 * @param url This URL will be loaded.
0348 * @param file Write into this file.
0349 * @throws IOException Reading or writing failed.
0350 */
0351 public static void saveFile(final URL url, final File file) throws IOException {
0352 saveFile(url.openStream(), file);
0353 }
0354
0355 /**
0356 * Save binary contents of an input stream into a file. The input stream is closed even
0357 * if exceptions occur. Existing files are overwritten.
0358 * @param in Read this stream.
0359 * @param file Write into this file.
0360 *
0361 * @throws IOException Reading or writing failed.
0362 */
0363 public static void saveFile(final InputStream in, final File file) throws IOException {
0364 FileOutputStream out = null;
0365 try {
0366 out = new FileOutputStream(file);
0367 final byte[] data = new byte[8 * 1024];
0368 int length;
0369 while ((length = in.read(data)) != -1) {
0370 out.write(data, 0, length);
0371 }
0372 } finally {
0373 close(in);
0374 close(out);
0375 }
0376 }
0377
0378 /**
0379 * Convert String into a {@link Reader}.
0380 *
0381 * <a href="http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4094886">
0382 * Bug ID: 4094886</a>
0383 *
0384 * @param data Convert this.
0385 * @return Resulting reader.
0386 */
0387 public static final Reader stringToReader(final String data) {
0388 try {
0389 return new InputStreamReader(new ByteArrayInputStream(data.getBytes("ISO-8859-1")));
0390 } catch (UnsupportedEncodingException e) {
0391 // should never occur
0392 throw new RuntimeException(e);
0393 }
0394 }
0395
0396 /**
0397 * Saves a <code>String</code> into a file. Existing files are overwritten.
0398 *
0399 * @param filename Name of the file (could include path).
0400 * @param text Data to save in the file.
0401 * @throws IOException File exception occurred.
0402 *
0403 * @deprecated Use {@link #saveFile(File, String, String)} that has an encoding.
0404 */
0405 public static void saveFile(final String filename, final String text)
0406 throws IOException {
0407 saveFile(new File(filename), text);
0408 }
0409
0410 /**
0411 * Saves a <code>StringBuffer</code> in a file. Existing files are overwritten.
0412 *
0413 * @param filename Name of the file (could include path).
0414 * @param text Data to save in the file.
0415 * @throws IOException File exception occurred.
0416 *
0417 * @deprecated Use {@link #saveFile(File, StringBuffer, String)} that has an encoding.
0418 */
0419 public static void saveFile(final String filename, final StringBuffer text)
0420 throws IOException {
0421 saveFile(new File(filename), text.toString());
0422 }
0423
0424 /**
0425 * Saves a <code>StringBuffer</code> in a file. Existing files are overwritten.
0426 *
0427 * @param file File to save into.
0428 * @param text Data to save in the file.
0429 * @throws IOException File exception occurred.
0430 *
0431 * @deprecated Use {@link #saveFile(File, StringBuffer, String)} that has an encoding
0432 * parameter.
0433 */
0434 public static void saveFile(final File file, final StringBuffer text)
0435 throws IOException {
0436 saveFile(file, text.toString());
0437 }
0438
0439 /**
0440 * Saves a <code>String</code> in a file. Uses default encoding. Existing files are
0441 * overwritten.
0442 *
0443 * @param file File to save the data in.
0444 * @param text Data to save in the file.
0445 * @throws IOException File exception occurred.
0446 *
0447 * @deprecated Use {@link #saveFile(File, String, String)} that has an encoding parameter.
0448 */
0449 public static void saveFile(final File file, final String text)
0450 throws IOException {
0451 BufferedWriter out = null;
0452 try {
0453 out = new BufferedWriter(new FileWriter(file));
0454 out.write(text);
0455 } finally {
0456 close(out);
0457 }
0458 }
0459
0460 /**
0461 * Saves a <code>String</code> in a file. Existing files are overwritten.
0462 *
0463 * @param file File to save the data in.
0464 * @param text Data to save in the file.
0465 * @param encoding Use this encoding.
0466 * @throws IOException File exception occurred.
0467 */
0468 public static void saveFile(final File file, final StringBuffer text, final String encoding)
0469 throws IOException {
0470 saveFile(file, text.toString(), encoding);
0471 }
0472
0473 /**
0474 * Saves a <code>String</code> in a file.
0475 *
0476 * @param file File to save the data in.
0477 * @param text Data to save in the file.
0478 * @param encoding Use this encoding.
0479 * @throws IOException File exception occurred.
0480 */
0481 public static void saveFile(final File file, final String text, final String encoding)
0482 throws IOException {
0483 BufferedWriter out = new BufferedWriter(
0484 new OutputStreamWriter(new FileOutputStream(file), encoding));
0485 try {
0486 out.write(text);
0487 } finally {
0488 out.close();
0489 }
0490 }
0491
0492 /**
0493 * Saves a <code>data</code> in a file. Existing files are overwritten.
0494 *
0495 * @param file File to save the data in.
0496 * @param data Data to save in the file.
0497 * @throws IOException File exception occurred.
0498 */
0499 public static void saveFileBinary(final File file, final byte[] data)
0500 throws IOException {
0501 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
0502 try {
0503 out.write(data);
0504 } finally {
0505 out.close();
0506 }
0507 }
0508
0509 /**
0510 * Copies a file to a different location.
0511 *
0512 * @param from Copy source.
0513 * @param to Copy destination.
0514 * @throws IOException File exception occurred.
0515 */
0516 public static void copyFile(final File from, final File to)
0517 throws IOException {
0518
0519 if (from.getCanonicalFile().equals(to.getCanonicalFile())) {
0520 return;
0521 }
0522 createNecessaryDirectories(to);
0523 FileInputStream in = null;
0524 FileOutputStream out = null;
0525 try {
0526 in = new FileInputStream(from);
0527 out = new FileOutputStream(to);
0528
0529 byte[] data = new byte[8 * 1024];
0530 int length;
0531 while ((length = in.read(data)) != -1) {
0532 out.write(data, 0, length);
0533 }
0534 } finally {
0535 close(in);
0536 close(out);
0537 }
0538 }
0539
0540 /**
0541 * Copy one file or directory to another location.
0542 * If targetLocation does not exist, it will be created.
0543 *
0544 * @param sourceLocation Copy from here. This can be a file or a directory.
0545 * @param targetLocation Copy to this location. If source is a file this must be a file too.
0546 * @throws IOException Something went wrong.
0547 */
0548 public static void copy(final String sourceLocation, final String targetLocation)
0549 throws IOException {
0550 copy(new File(sourceLocation), new File(targetLocation));
0551 }
0552
0553 /**
0554 * Copy one directory to another location.
0555 * If targetLocation does not exist, it will be created.
0556 *
0557 * @param sourceLocation Copy from here.
0558 * @param targetLocation Copy to this location
0559 * @throws IOException Something went wrong.
0560 */
0561 public static void copy(final File sourceLocation, final File targetLocation)
0562 throws IOException {
0563
0564 if (sourceLocation.isDirectory()) {
0565 if (!targetLocation.exists()) {
0566 targetLocation.mkdir();
0567 }
0568 String[] children = sourceLocation.list();
0569 for (int i = 0; i < children.length; i++) { // recursive call for all children
0570 copy(new File(sourceLocation, children[i]),
0571 new File(targetLocation, children[i]));
0572 }
0573 } else { // copy file
0574 copyFile(sourceLocation, targetLocation);
0575 }
0576 }
0577
0578 /**
0579 * List all matching files. Searches all matching sub directories recursively.
0580 * Remember to return <code>true</code> for <code>accept(File pathname)</code> if
0581 * <code>pathname</code> is a directory if you want to search all sub directories!
0582 * If <code>sourceLocation</code> is a single file, this is the only file that will
0583 * be in the resulting list.
0584 *
0585 * @param sourceLocation Check all files in this directory. (Or add this single file.)
0586 * @param filter Accept only these directories and files.
0587 * @return List of matching files. Contains no directories.
0588 * @throws IOException Something went wrong.
0589 */
0590 public static List listFilesRecursively(final File sourceLocation, final FileFilter filter)
0591 throws IOException {
0592 final List result = new ArrayList();
0593 if (sourceLocation.isDirectory()) {
0594 final File[] children = sourceLocation.listFiles();
0595 for (int i = 0; i < children.length; i++) { // recursive call for all children
0596 result.addAll(listFilesRecursivelyIntern(children[i], filter));
0597 }
0598 } else {
0599 result.add(sourceLocation);
0600 }
0601 return result;
0602 }
0603
0604 /**
0605 * List all matching files. Searches all matching sub directories recursively.
0606 * Remember to return <code>true</code> for <code>accept(File pathname)</code> if
0607 * <code>pathname</code> is a directory if you want to search all sub directories!
0608 *
0609 * @param sourceLocation Check all files in this directory.
0610 * @param filter Accept only these directories and files.
0611 * @return List of matching files. Contains no directories.
0612 * @throws IOException Something went wrong.
0613 */
0614 private static List listFilesRecursivelyIntern(final File sourceLocation,
0615 final FileFilter filter) throws IOException {
0616 final List result = new ArrayList();
0617 if (filter.accept(sourceLocation)) {
0618 if (sourceLocation.isDirectory()) {
0619 File[] children = sourceLocation.listFiles();
0620 for (int i = 0; i < children.length; i++) { // recursive call for all children
0621 result.addAll(listFilesRecursivelyIntern(children[i], filter));
0622 }
0623 } else {
0624 result.add(sourceLocation);
0625 }
0626 }
0627 return result;
0628 }
0629
0630 /**
0631 * Compare two files binary.
0632 *
0633 * @param from Compare source. This file must be <code>null</code> or be an existing file.
0634 * @param with Compare with this file. This file must be <code>null</code> or be an
0635 * existing file.
0636 * @return Is the contents of the two files binary equal?
0637 * @throws IOException File exception occurred.
0638 */
0639 public static boolean compareFilesBinary(final File from, final File with)
0640 throws IOException {
0641 if (from == null && with == null) {
0642 return true;
0643 }
0644 if (from == null || with == null) {
0645 return false;
0646 }
0647 if (from.getAbsoluteFile().equals(with.getAbsoluteFile())) {
0648 return true;
0649 }
0650 if (from.length() != with.length()) {
0651 return false;
0652 }
0653 byte[] dataOne = new byte[8 * 1024];
0654 byte[] dataTwo = new byte[8 * 1024];
0655 int length;
0656
0657 FileInputStream one = null;
0658 FileInputStream two = null;
0659 try {
0660 one = new FileInputStream(from);
0661 two = new FileInputStream(with);
0662
0663 while ((length = one.read(dataOne)) != -1) {
0664 if (length != two.read(dataTwo)) {
0665 return false;
0666 }
0667 if (!Arrays.equals(dataOne, dataTwo)) {
0668 return false;
0669 }
0670 }
0671 return true;
0672 } finally {
0673 close(one);
0674 close(two);
0675 }
0676 }
0677
0678 /**
0679 * Compare two text files. Ignores different line separators. As there are:
0680 * LF, CR, CR + LF, NEL, FF, LS, PS.
0681 *
0682 * @param from Compare source.
0683 * @param with Compare with this file.
0684 * @param encoding Use this character encoding. Must not be <code>null</code>.
0685 * @return Is the contents of the two text files equal?
0686 * @throws IOException File exception occurred or encoding is not supported.
0687 * @throws NullPointerException Is encoding different from <code>null</code>?
0688 */
0689 public static boolean compareTextFiles(final File from, final File with, final String encoding)
0690 throws IOException {
0691 if (from == null && with == null) {
0692 return true;
0693 }
0694 if (from == null || with == null) {
0695 return false;
0696 }
0697 if (from.getAbsoluteFile().equals(with.getAbsoluteFile())) {
0698 return true;
0699 }
0700
0701 BufferedReader one = null;
0702 BufferedReader two = null;
0703 FileInputStream fromIn = null;
0704 FileInputStream withIn = null;
0705 try {
0706 fromIn = new FileInputStream(from);
0707 one = new BufferedReader(new InputStreamReader(fromIn, encoding));
0708 withIn = new FileInputStream(with);
0709 two = new BufferedReader(new InputStreamReader(withIn, encoding));
0710
0711 boolean crOne = false;
0712 boolean crTwo = false;
0713 do {
0714 int readOne = one.read();
0715 int readTwo = two.read();
0716 if (readOne == readTwo) {
0717 if (readOne < 0) {
0718 break;
0719 }
0720 } else {
0721 crOne = readOne == 0x0D;
0722 crTwo = readTwo == 0x0D;
0723 if (crOne) {
0724 readOne = one.read();
0725 }
0726 if (crTwo) {
0727 readTwo = two.read();
0728 }
0729 if (crOne && readOne != 0x0A && isCr(readTwo)) {
0730 readTwo = two.read();
0731 }
0732 if (crTwo && readTwo != 0x0A && isCr(readOne)) {
0733 readOne = one.read();
0734 }
0735 if (readOne != readTwo && (!isCr(readOne) && !isCr(readTwo))) {
0736 return false;
0737 }
0738 }
0739 } while (true);
0740 return true;
0741 } finally {
0742 close(fromIn);
0743 close(one);
0744 close(two);
0745 close(withIn);
0746 }
0747 }
0748
0749 /**
0750 * Compare two text files. Ignores different line separators. As there are:
0751 * LF, CR, CR + LF
0752 *
0753 * @param from Compare source.
0754 * @param with Compare with this file.
0755 * @param startAtLine Start comparing at this line (beginning with 0).
0756 * @param encoding Use this character encoding. Must not be <code>null</code>.
0757 * @return Is the contents of the two text files equal?
0758 * @throws IOException File exception occurred or encoding is not supported.
0759 * @throws NullPointerException Is encoding different from <code>null</code>?
0760 */
0761 public static boolean compareTextFiles(final File from, final File with, final int startAtLine,
0762 final String encoding) throws IOException {
0763
0764 if (from == null && with == null) {
0765 return true;
0766 }
0767 if (from == null || with == null) {
0768 return false;
0769 }
0770 if (from.getAbsoluteFile().equals(with.getAbsoluteFile())) {
0771 return true;
0772 }
0773 if (startAtLine < 0) {
0774 return true;
0775 }
0776 BufferedReader one = null;
0777 BufferedReader two = null;
0778 FileInputStream fromIn = null;
0779 FileInputStream withIn = null;
0780 try {
0781 fromIn = new FileInputStream(from);
0782 one = new BufferedReader(new InputStreamReader(fromIn, encoding));
0783 withIn = new FileInputStream(with);
0784 two = new BufferedReader(new InputStreamReader(withIn, encoding));
0785 int pos = 0;
0786 do {
0787 String lineOne = one.readLine();
0788 String lineTwo = two.readLine();
0789 if (lineOne == null) {
0790 if (lineTwo == null) {
0791 break;
0792 }
0793 return false;
0794 }
0795 if (pos++ >= startAtLine && !lineOne.equals(lineTwo)) {
0796 return false;
0797 }
0798 } while (true);
0799 return true;
0800 } finally {
0801 close(fromIn);
0802 close(one);
0803 close(two);
0804 close(withIn);
0805 }
0806 }
0807
0808 /**
0809 * Test if character is LF, CR, NEL, FF, LS, PS.
0810 * @param c Character to test.
0811 * @return Is character a line terminator?
0812 */
0813 private static boolean isCr(final int c) {
0814 return c == 0x0A || c == 0x0D || c == 0x85 || c == 0x0C || c == 0x2028 || c == 0x2029;
0815 }
0816
0817 /**
0818 * Delete file directory recursive.
0819 *
0820 * @param directory Directory to delete. Must not be a symbolic link.
0821 * @param deleteDir Delete directory itself too?
0822 * @return Was deletion successful?
0823 */
0824 public static boolean deleteDir(final File directory, final boolean deleteDir) {
0825
0826 // first we check if the file is a symbolic link
0827 try {
0828 if (isSymbolicLink(directory)) {
0829 return false;
0830 }
0831 } catch (IOException e) {
0832 return false;
0833 }
0834 final File candir;
0835 try {
0836 candir = directory.getCanonicalFile();
0837 } catch (IOException e) {
0838 return false;
0839 }
0840
0841 // now we go through all of the files and subdirectories in the
0842 // directory and delete them one by one
0843 boolean success = true;
0844 File[] files = candir.listFiles();
0845 if (files != null) {
0846 for (int i = 0; i < files.length; i++) {
0847 File file = files[i];
0848
0849 // in case this directory is actually a symbolic link, or it's
0850 // empty, we want to try to delete the link before we try
0851 // anything
0852 boolean deleted = file.delete();
0853 if (!deleted) {
0854 // deleting the file failed, so maybe it's a non-empty
0855 // directory
0856 if (file.isDirectory()) {
0857 deleted = deleteDir(file, true);
0858 }
0859
0860 // otherwise, there's nothing else we can do
0861 }
0862 success = success && deleted;
0863 }
0864 }
0865
0866 // now that we tried to clear the directory out, we can try to delete it
0867 if (deleteDir && directory.exists()) {
0868 return directory.delete();
0869 }
0870 return success;
0871 }
0872
0873 /**
0874 * Delete directory contents for all files that match the filter. The main directory itself is
0875 * not deleted.
0876 *
0877 * @param directory Directory to scan for files to delete.
0878 * @param filter Filter files (and directories) to delete.
0879 * @return Was deletion successful?
0880 */
0881 public static boolean deleteDir(final File directory, final FileFilter filter) {
0882 // first we check if the file is a symbolic link
0883 try {
0884 if (isSymbolicLink(directory)) {
0885 return false;
0886 }
0887 } catch (IOException e) {
0888 return false;
0889 }
0890 final File candir;
0891 try {
0892 candir = directory.getCanonicalFile();
0893 } catch (IOException e) {
0894 return false;
0895 }
0896
0897 // now we go through all of the files and subdirectories in the
0898 // directory and delete them one by one
0899 boolean success = true;
0900 File[] files = candir.listFiles(filter);
0901 if (files != null) {
0902 for (int i = 0; i < files.length; i++) {
0903 File file = files[i];
0904
0905 // in case this directory is actually a symbolic link, or it's
0906 // empty, we want to try to delete the link before we try
0907 // anything
0908 boolean deleted = file.delete();
0909 if (!deleted) {
0910 // deleting the file failed, so maybe it's a non-empty
0911 // directory
0912 if (file.isDirectory()) {
0913 deleted = deleteDir(file, true);
0914 }
0915
0916 // otherwise, there's nothing else we can do
0917 }
0918 success = success && deleted;
0919 }
0920 }
0921
0922 return success;
0923 }
0924
0925 /**
0926 * Determines whether the specified file is a symbolic link rather than an actual file.
0927 * See {@link
0928 * https://svn.apache.org/repos/asf/commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java}.
0929 * @param file File to check.
0930 * @return Is the file is a symbolic link?
0931 * @throws IOException IO error while checking the file.
0932 */
0933 public static boolean isSymbolicLink(final File file) throws IOException {
0934 if (file == null) {
0935 throw new NullPointerException("File must not be null");
0936 }
0937 // is windows file system in use?
0938 if (File.separatorChar == '\\') {
0939 // we have no symbolic links
0940 return false;
0941 }
0942 File fileInCanonicalDir = null;
0943 if (file.getParent() == null) {
0944 fileInCanonicalDir = file;
0945 } else {
0946 File canonicalDir = file.getParentFile().getCanonicalFile();
0947 fileInCanonicalDir = new File(canonicalDir, file.getName());
0948 }
0949 if (fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) {
0950 return false;
0951 }
0952 return true;
0953 }
0954
0955 /**
0956 * Print current system properties to System.out.
0957 */
0958 public static void printAllSystemProperties() {
0959 Properties sysprops = System.getProperties();
0960 for (Enumeration e = sysprops.propertyNames(); e.hasMoreElements(); ) {
0961 String key = (String) e.nextElement();
0962 String value = sysprops.getProperty(key);
0963 System.out.println(key + "=" + value);
0964 }
0965 }
0966
0967 /**
0968 * Get home directory of user.
0969 *
0970 * @return Home directory of user.
0971 */
0972 public static File getUserHomeDirectory() {
0973 return new File((String) System.getProperties().get("user.home"));
0974 }
0975
0976 /**
0977 * Creates necessary parent directories for a file.
0978 *
0979 * @param file File.
0980 * @throws IOException Creation failed.
0981 */
0982 public static void createNecessaryDirectories(final File file) throws IOException {
0983 if (file != null && file.getParentFile() != null) {
0984 file.getParentFile().mkdirs();
0985 if (!file.getParentFile().exists()) {
0986 throw new IOException("directory creation failed: " + file.getParent());
0987 }
0988 }
0989 }
0990
0991 /**
0992 * Create relative address from <code>origin</code> to <code>next</code>.
0993 * The resulting file path has "/" as directory name separator.
0994 * If the resulting file path is the same as origin specifies, we return "".
0995 * Otherwise the result will always have an "/" as last character.
0996 *
0997 * @param origin This is the original location. Must be a directory.
0998 * @param next This should be the next location. Must also be a directory.
0999 * @return Relative (or if necessary absolute) file path.
1000 */
1001 public static final String createRelativePath(final File origin, final File next) {
1002 if (origin.equals(next)) {
1003 return "";
1004 }
1005 final Path org = new Path(origin.getPath().replace(File.separatorChar, '/'), "");
1006 final Path ne = new Path(next.getPath().replace(File.separatorChar, '/'), "");
1007 return org.createRelative(ne.toString()).toString();
1008 }
1009
1010 /**
1011 * Waits until a '\n' was read from System.in.
1012 */
1013 public static void waitln() {
1014 System.out.println("\n..press <return> to continue");
1015 try {
1016 (new java.io.BufferedReader(new java.io.InputStreamReader(
1017 System.in))).readLine();
1018 } catch (IOException e) {
1019 // ignore
1020 }
1021 }
1022
1023 /**
1024 * Closes input stream without exception.
1025 *
1026 * @param in Input stream, maybe <code>null</code>.
1027 */
1028 public static void close(final InputStream in) {
1029 if (in != null) {
1030 try {
1031 in.close();
1032 } catch (Exception e) {
1033 // ignore
1034 }
1035 }
1036 }
1037
1038 /**
1039 * Closes writer without exception.
1040 *
1041 * @param writer Writer, maybe <code>null</code>.
1042 */
1043 public static void close(final Writer writer) {
1044 if (writer != null) {
1045 try {
1046 writer.close();
1047 } catch (Exception e) {
1048 // ignore
1049 }
1050 }
1051 }
1052
1053 /**
1054 * Closes out stream without exception.
1055 *
1056 * @param out Output stream, maybe <code>null</code>.
1057 */
1058 public static void close(final OutputStream out) {
1059 if (out != null) {
1060 try {
1061 out.close();
1062 } catch (Exception e) {
1063 // ignore
1064 }
1065 }
1066 }
1067
1068 /**
1069 * Closes input reader without exception.
1070 *
1071 * @param reader Reader, maybe <code>null</code>.
1072 */
1073 public static void close(final Reader reader) {
1074 if (reader != null) {
1075 try {
1076 reader.close();
1077 } catch (Exception e) {
1078 // ignore
1079 }
1080 }
1081 }
1082
1083 /**
1084 * Get start directory for application. Within the start directory all newly created data is
1085 * stored in. If this is no Java Webstart version the result is
1086 * <code>new File(".")</code>. Otherwise the start directory is the subdirectory
1087 * "." concatenated <code>application</code> within <code>user.home</code>.
1088 *
1089 * @param application Application name, used for Java Webstart version. Should
1090 * be written in lowercase letters. A "." is automatically appended at
1091 * the beginning.
1092 * @return Start directory for application.
1093 */
1094 public static final File getStartDirectory(final String application) {
1095 final File startDirectory;
1096 if (isWebStarted()) {
1097 startDirectory = new File(getUserHomeDirectory(), "." + application);
1098 } else {
1099 startDirectory = new File(".");
1100 }
1101 return startDirectory;
1102 }
1103
1104 /**
1105 * Was the application started by Java Webstart?
1106 *
1107 * @return Was the application started by Java Webstart.
1108 */
1109 public static final boolean isWebStarted() {
1110 final String webStart = (String) System.getProperties().get("javawebstart.version");
1111 return webStart != null;
1112 }
1113
1114 /**
1115 * Loads a property file from given URL.
1116 *
1117 * @param url URL to load properties from. Must not be <code>null</code>.
1118 * @return Loaded properties.
1119 * @throws IOException Reading error.
1120 */
1121 public static Properties loadProperties(final URL url)
1122 throws IOException {
1123 Properties newprops = new Properties();
1124 InputStream in = null;
1125 try {
1126 in = url.openStream();
1127 newprops.load(in);
1128 } finally {
1129 close(in);
1130 }
1131 return newprops;
1132 }
1133
1134 /**
1135 * Sleep my little class.
1136 *
1137 * @param ms Milliseconds to wait.
1138 */
1139 public static void sleep(final int ms) {
1140 final Object monitor = new Object();
1141 synchronized (monitor) {
1142 try {
1143 monitor.wait(ms);
1144 } catch (InterruptedException e) {
1145 }
1146 }
1147 }
1148
1149 /**
1150 * Get currently running java version and subversion numbers. This is the running JRE version.
1151 * If no version could be identified <code>null</code> is returned.
1152 *
1153 * @return Array of version and subversion numbers.
1154 */
1155 public static int[] getJavaVersion() {
1156 final String version = System.getProperty("java.version");
1157 final List numbers = new ArrayList();
1158 final StringTokenizer tokenizer = new StringTokenizer(version, ".");
1159 while (tokenizer.hasMoreElements()) {
1160 String sub = (String) tokenizer.nextToken();
1161 for (int i = 0; i < sub.length(); i++) {
1162 if (!Character.isDigit(sub.charAt(i))) {
1163 sub = sub.substring(0, i);
1164 break;
1165 }
1166 }
1167 try {
1168 numbers.add(new Integer(Integer.parseInt(sub)));
1169 } catch (Exception e) {
1170 e.printStackTrace();
1171 break;
1172 }
1173 }
1174 if (numbers.size() == 0) {
1175 return null;
1176 }
1177 final int[] result = new int[numbers.size()];
1178 for (int i = 0; i < numbers.size(); i++) {
1179 result[i] = ((Integer) numbers.get(i)).intValue();
1180 }
1181 return result;
1182 }
1183
1184 /**
1185 * Get key sorted list of all System Properties.
1186 *
1187 * @return Array with the two columns key and value.
1188 */
1189 public static String[][] getSortedSystemProperties() {
1190 final Map map = new TreeMap(System.getProperties());
1191 String[][] rowData = new String[map.size()][2];
1192 int rowNum = 0;
1193 final Iterator iterator = map.entrySet().iterator();
1194 while (iterator.hasNext()) {
1195 Map.Entry entry = (Map.Entry) iterator.next();
1196 rowData[rowNum][0] = (String) entry.getKey();
1197 rowData[rowNum][1] = (String) entry.getValue();
1198 rowNum++;
1199 }
1200 return rowData;
1201 }
1202
1203 }
|