0001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
0002 *
0003 * Copyright 2000-2014, 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 createNecessaryDirectories(file);
0365 FileOutputStream out = null;
0366 try {
0367 out = new FileOutputStream(file);
0368 final byte[] data = new byte[8 * 1024];
0369 int length;
0370 while ((length = in.read(data)) != -1) {
0371 out.write(data, 0, length);
0372 }
0373 } finally {
0374 close(in);
0375 close(out);
0376 }
0377 }
0378
0379 /**
0380 * Convert String into a {@link Reader}.
0381 *
0382 * <a href="http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4094886">
0383 * Bug ID: 4094886</a>
0384 *
0385 * @param data Convert this.
0386 * @return Resulting reader.
0387 */
0388 public static final Reader stringToReader(final String data) {
0389 try {
0390 return new InputStreamReader(new ByteArrayInputStream(data.getBytes("ISO-8859-1")));
0391 } catch (UnsupportedEncodingException e) {
0392 // should never occur
0393 throw new RuntimeException(e);
0394 }
0395 }
0396
0397 /**
0398 * Saves a <code>String</code> into a file. Existing files are overwritten.
0399 *
0400 * @param filename Name of the file (could include path).
0401 * @param text Data to save in the file.
0402 * @throws IOException File exception occurred.
0403 *
0404 * @deprecated Use {@link #saveFile(File, String, String)} that has an encoding.
0405 */
0406 public static void saveFile(final String filename, final String text)
0407 throws IOException {
0408 saveFile(new File(filename), text);
0409 }
0410
0411 /**
0412 * Saves a <code>StringBuffer</code> in a file. Existing files are overwritten.
0413 *
0414 * @param filename Name of the file (could include path).
0415 * @param text Data to save in the file.
0416 * @throws IOException File exception occurred.
0417 *
0418 * @deprecated Use {@link #saveFile(File, StringBuffer, String)} that has an encoding.
0419 */
0420 public static void saveFile(final String filename, final StringBuffer text)
0421 throws IOException {
0422 saveFile(new File(filename), text.toString());
0423 }
0424
0425 /**
0426 * Saves a <code>StringBuffer</code> in a file. Existing files are overwritten.
0427 *
0428 * @param file File to save into.
0429 * @param text Data to save in the file.
0430 * @throws IOException File exception occurred.
0431 *
0432 * @deprecated Use {@link #saveFile(File, StringBuffer, String)} that has an encoding
0433 * parameter.
0434 */
0435 public static void saveFile(final File file, final StringBuffer text)
0436 throws IOException {
0437 saveFile(file, text.toString());
0438 }
0439
0440 /**
0441 * Saves a <code>String</code> in a file. Uses default encoding. Existing files are
0442 * overwritten.
0443 *
0444 * @param file File to save the data in.
0445 * @param text Data to save in the file.
0446 * @throws IOException File exception occurred.
0447 *
0448 * @deprecated Use {@link #saveFile(File, String, String)} that has an encoding parameter.
0449 */
0450 public static void saveFile(final File file, final String text)
0451 throws IOException {
0452 createNecessaryDirectories(file);
0453 BufferedWriter out = null;
0454 try {
0455 out = new BufferedWriter(new FileWriter(file));
0456 out.write(text);
0457 } finally {
0458 close(out);
0459 }
0460 }
0461
0462 /**
0463 * Saves a <code>String</code> in a file. Existing files are overwritten.
0464 *
0465 * @param file File to save the data in.
0466 * @param text Data to save in the file.
0467 * @param encoding Use this encoding.
0468 * @throws IOException File exception occurred.
0469 */
0470 public static void saveFile(final File file, final StringBuffer text, final String encoding)
0471 throws IOException {
0472 saveFile(file, text.toString(), encoding);
0473 }
0474
0475 /**
0476 * Saves a <code>String</code> in a file.
0477 *
0478 * @param file File to save the data in.
0479 * @param text Data to save in the file.
0480 * @param encoding Use this encoding.
0481 * @throws IOException File exception occurred.
0482 */
0483 public static void saveFile(final File file, final String text, final String encoding)
0484 throws IOException {
0485 createNecessaryDirectories(file);
0486 BufferedWriter out = new BufferedWriter(
0487 new OutputStreamWriter(new FileOutputStream(file), encoding));
0488 try {
0489 out.write(text);
0490 } finally {
0491 out.close();
0492 }
0493 }
0494
0495 /**
0496 * Saves a <code>data</code> in a file. Existing files are overwritten.
0497 *
0498 * @param file File to save the data in.
0499 * @param data Data to save in the file.
0500 * @throws IOException File exception occurred.
0501 */
0502 public static void saveFileBinary(final File file, final byte[] data)
0503 throws IOException {
0504 createNecessaryDirectories(file);
0505 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
0506 try {
0507 out.write(data);
0508 } finally {
0509 out.close();
0510 }
0511 }
0512
0513 /**
0514 * Copies a file to a different location.
0515 *
0516 * @param from Copy source.
0517 * @param to Copy destination.
0518 * @throws IOException File exception occurred.
0519 */
0520 public static void copyFile(final File from, final File to)
0521 throws IOException {
0522
0523 if (from.getCanonicalFile().equals(to.getCanonicalFile())) {
0524 return;
0525 }
0526 createNecessaryDirectories(to);
0527 FileInputStream in = null;
0528 FileOutputStream out = null;
0529 try {
0530 in = new FileInputStream(from);
0531 out = new FileOutputStream(to);
0532
0533 byte[] data = new byte[8 * 1024];
0534 int length;
0535 while ((length = in.read(data)) != -1) {
0536 out.write(data, 0, length);
0537 }
0538 } finally {
0539 close(in);
0540 close(out);
0541 }
0542 }
0543
0544 /**
0545 * Copy one file or directory to another location.
0546 * If targetLocation does not exist, it will be created.
0547 *
0548 * @param sourceLocation Copy from here. This can be a file or a directory.
0549 * @param targetLocation Copy to this location. If source is a file this must be a file too.
0550 * @throws IOException Something went wrong.
0551 */
0552 public static void copy(final String sourceLocation, final String targetLocation)
0553 throws IOException {
0554 copy(new File(sourceLocation), new File(targetLocation));
0555 }
0556
0557 /**
0558 * Copy one directory to another location.
0559 * If targetLocation does not exist, it will be created.
0560 *
0561 * @param sourceLocation Copy from here.
0562 * @param targetLocation Copy to this location
0563 * @throws IOException Something went wrong.
0564 */
0565 public static void copy(final File sourceLocation, final File targetLocation)
0566 throws IOException {
0567
0568 if (sourceLocation.isDirectory()) {
0569 if (!targetLocation.exists()) {
0570 targetLocation.mkdir();
0571 }
0572 String[] children = sourceLocation.list();
0573 for (int i = 0; i < children.length; i++) { // recursive call for all children
0574 copy(new File(sourceLocation, children[i]),
0575 new File(targetLocation, children[i]));
0576 }
0577 } else { // copy file
0578 copyFile(sourceLocation, targetLocation);
0579 }
0580 }
0581
0582 /**
0583 * List all matching files. Searches all matching sub directories recursively.
0584 * Remember to return <code>true</code> for <code>accept(File pathname)</code> if
0585 * <code>pathname</code> is a directory if you want to search all sub directories!
0586 * If <code>sourceLocation</code> is a single file, this is the only file that will
0587 * be in the resulting list.
0588 *
0589 * @param sourceLocation Check all files in this directory. (Or add this single file.)
0590 * @param filter Accept only these directories and files.
0591 * @return List of matching files. Contains no directories.
0592 * @throws IOException Something went wrong.
0593 */
0594 public static List listFilesRecursively(final File sourceLocation, final FileFilter filter)
0595 throws IOException {
0596 final List result = new ArrayList();
0597 if (sourceLocation.isDirectory()) {
0598 final File[] children = sourceLocation.listFiles();
0599 for (int i = 0; i < children.length; i++) { // recursive call for all children
0600 result.addAll(listFilesRecursivelyIntern(children[i], filter));
0601 }
0602 } else {
0603 result.add(sourceLocation);
0604 }
0605 return result;
0606 }
0607
0608 /**
0609 * List all matching files. Searches all matching sub directories recursively.
0610 * Remember to return <code>true</code> for <code>accept(File pathname)</code> if
0611 * <code>pathname</code> is a directory if you want to search all sub directories!
0612 *
0613 * @param sourceLocation Check all files in this directory.
0614 * @param filter Accept only these directories and files.
0615 * @return List of matching files. Contains no directories.
0616 * @throws IOException Something went wrong.
0617 */
0618 private static List listFilesRecursivelyIntern(final File sourceLocation,
0619 final FileFilter filter) throws IOException {
0620 final List result = new ArrayList();
0621 if (filter.accept(sourceLocation)) {
0622 if (sourceLocation.isDirectory()) {
0623 File[] children = sourceLocation.listFiles();
0624 for (int i = 0; i < children.length; i++) { // recursive call for all children
0625 result.addAll(listFilesRecursivelyIntern(children[i], filter));
0626 }
0627 } else {
0628 result.add(sourceLocation);
0629 }
0630 }
0631 return result;
0632 }
0633
0634 /**
0635 * Compare two files binary.
0636 *
0637 * @param from Compare source. This file must be <code>null</code> or be an existing file.
0638 * @param with Compare with this file. This file must be <code>null</code> or be an
0639 * existing file.
0640 * @return Is the contents of the two files binary equal?
0641 * @throws IOException File exception occurred.
0642 */
0643 public static boolean compareFilesBinary(final File from, final File with)
0644 throws IOException {
0645 if (from == null && with == null) {
0646 return true;
0647 }
0648 if (from == null || with == null) {
0649 return false;
0650 }
0651 if (from.getAbsoluteFile().equals(with.getAbsoluteFile())) {
0652 return true;
0653 }
0654 if (from.length() != with.length()) {
0655 return false;
0656 }
0657 byte[] dataOne = new byte[8 * 1024];
0658 byte[] dataTwo = new byte[8 * 1024];
0659 int length;
0660
0661 FileInputStream one = null;
0662 FileInputStream two = null;
0663 try {
0664 one = new FileInputStream(from);
0665 two = new FileInputStream(with);
0666
0667 while ((length = one.read(dataOne)) != -1) {
0668 if (length != two.read(dataTwo)) {
0669 return false;
0670 }
0671 if (!Arrays.equals(dataOne, dataTwo)) {
0672 return false;
0673 }
0674 }
0675 return true;
0676 } finally {
0677 close(one);
0678 close(two);
0679 }
0680 }
0681
0682 /**
0683 * Compare two text files. Ignores different line separators. As there are:
0684 * LF, CR, CR + LF, NEL, FF, LS, PS.
0685 *
0686 * @param from Compare source.
0687 * @param with Compare with this file.
0688 * @param encoding Use this character encoding. Must not be <code>null</code>.
0689 * @return Is the contents of the two text files equal?
0690 * @throws IOException File exception occurred or encoding is not supported.
0691 * @throws NullPointerException Is encoding different from <code>null</code>?
0692 */
0693 public static boolean compareTextFiles(final File from, final File with, final String encoding)
0694 throws IOException {
0695 if (from == null && with == null) {
0696 return true;
0697 }
0698 if (from == null || with == null) {
0699 return false;
0700 }
0701 if (from.getAbsoluteFile().equals(with.getAbsoluteFile())) {
0702 return true;
0703 }
0704
0705 BufferedReader one = null;
0706 BufferedReader two = null;
0707 FileInputStream fromIn = null;
0708 FileInputStream withIn = null;
0709 try {
0710 fromIn = new FileInputStream(from);
0711 one = new BufferedReader(new InputStreamReader(fromIn, encoding));
0712 withIn = new FileInputStream(with);
0713 two = new BufferedReader(new InputStreamReader(withIn, encoding));
0714
0715 boolean crOne = false;
0716 boolean crTwo = false;
0717 do {
0718 int readOne = one.read();
0719 int readTwo = two.read();
0720 if (readOne == readTwo) {
0721 if (readOne < 0) {
0722 break;
0723 }
0724 } else {
0725 crOne = readOne == 0x0D;
0726 crTwo = readTwo == 0x0D;
0727 if (crOne) {
0728 readOne = one.read();
0729 }
0730 if (crTwo) {
0731 readTwo = two.read();
0732 }
0733 if (crOne && readOne != 0x0A && isCr(readTwo)) {
0734 readTwo = two.read();
0735 }
0736 if (crTwo && readTwo != 0x0A && isCr(readOne)) {
0737 readOne = one.read();
0738 }
0739 if (readOne != readTwo && (!isCr(readOne) && !isCr(readTwo))) {
0740 return false;
0741 }
0742 }
0743 } while (true);
0744 return true;
0745 } finally {
0746 close(fromIn);
0747 close(one);
0748 close(two);
0749 close(withIn);
0750 }
0751 }
0752
0753 /**
0754 * Compare two text files. Ignores different line separators. As there are:
0755 * LF, CR, CR + LF
0756 *
0757 * @param from Compare source.
0758 * @param with Compare with this file.
0759 * @param startAtLine Start comparing at this line (beginning with 0).
0760 * @param encoding Use this character encoding. Must not be <code>null</code>.
0761 * @return Is the contents of the two text files equal?
0762 * @throws IOException File exception occurred or encoding is not supported.
0763 * @throws NullPointerException Is encoding different from <code>null</code>?
0764 */
0765 public static boolean compareTextFiles(final File from, final File with, final int startAtLine,
0766 final String encoding) throws IOException {
0767
0768 if (from == null && with == null) {
0769 return true;
0770 }
0771 if (from == null || with == null) {
0772 return false;
0773 }
0774 if (from.getAbsoluteFile().equals(with.getAbsoluteFile())) {
0775 return true;
0776 }
0777 if (startAtLine < 0) {
0778 return true;
0779 }
0780 BufferedReader one = null;
0781 BufferedReader two = null;
0782 FileInputStream fromIn = null;
0783 FileInputStream withIn = null;
0784 try {
0785 fromIn = new FileInputStream(from);
0786 one = new BufferedReader(new InputStreamReader(fromIn, encoding));
0787 withIn = new FileInputStream(with);
0788 two = new BufferedReader(new InputStreamReader(withIn, encoding));
0789 int pos = 0;
0790 do {
0791 String lineOne = one.readLine();
0792 String lineTwo = two.readLine();
0793 if (lineOne == null) {
0794 if (lineTwo == null) {
0795 break;
0796 }
0797 return false;
0798 }
0799 if (pos++ >= startAtLine && !lineOne.equals(lineTwo)) {
0800 return false;
0801 }
0802 } while (true);
0803 return true;
0804 } finally {
0805 close(fromIn);
0806 close(one);
0807 close(two);
0808 close(withIn);
0809 }
0810 }
0811
0812 /**
0813 * Test if character is LF, CR, NEL, FF, LS, PS.
0814 * @param c Character to test.
0815 * @return Is character a line terminator?
0816 */
0817 private static boolean isCr(final int c) {
0818 return c == 0x0A || c == 0x0D || c == 0x85 || c == 0x0C || c == 0x2028 || c == 0x2029;
0819 }
0820
0821 /**
0822 * Delete file directory recursive.
0823 *
0824 * @param directory Directory to delete. Must not be a symbolic link.
0825 * @param deleteDir Delete directory itself too?
0826 * @return Was deletion successful?
0827 */
0828 public static boolean deleteDir(final File directory, final boolean deleteDir) {
0829
0830 // first we check if the file is a symbolic link
0831 try {
0832 if (isSymbolicLink(directory)) {
0833 return false;
0834 }
0835 } catch (IOException e) {
0836 return false;
0837 }
0838 final File candir;
0839 try {
0840 candir = directory.getCanonicalFile();
0841 } catch (IOException e) {
0842 return false;
0843 }
0844
0845 // now we go through all of the files and subdirectories in the
0846 // directory and delete them one by one
0847 boolean success = true;
0848 File[] files = candir.listFiles();
0849 if (files != null) {
0850 for (int i = 0; i < files.length; i++) {
0851 File file = files[i];
0852
0853 // in case this directory is actually a symbolic link, or it's
0854 // empty, we want to try to delete the link before we try
0855 // anything
0856 boolean deleted = file.delete();
0857 if (!deleted) {
0858 // deleting the file failed, so maybe it's a non-empty
0859 // directory
0860 if (file.isDirectory()) {
0861 deleted = deleteDir(file, true);
0862 }
0863
0864 // otherwise, there's nothing else we can do
0865 }
0866 success = success && deleted;
0867 }
0868 }
0869
0870 // now that we tried to clear the directory out, we can try to delete it
0871 if (deleteDir && directory.exists()) {
0872 return directory.delete();
0873 }
0874 return success;
0875 }
0876
0877 /**
0878 * Delete directory contents for all files that match the filter. The main directory itself is
0879 * not deleted.
0880 *
0881 * @param directory Directory to scan for files to delete.
0882 * @param filter Filter files (and directories) to delete.
0883 * @return Was deletion successful?
0884 */
0885 public static boolean deleteDir(final File directory, final FileFilter filter) {
0886 // first we check if the file is a symbolic link
0887 try {
0888 if (isSymbolicLink(directory)) {
0889 return false;
0890 }
0891 } catch (IOException e) {
0892 return false;
0893 }
0894 final File candir;
0895 try {
0896 candir = directory.getCanonicalFile();
0897 } catch (IOException e) {
0898 return false;
0899 }
0900
0901 // now we go through all of the files and subdirectories in the
0902 // directory and delete them one by one
0903 boolean success = true;
0904 File[] files = candir.listFiles(filter);
0905 if (files != null) {
0906 for (int i = 0; i < files.length; i++) {
0907 File file = files[i];
0908
0909 // in case this directory is actually a symbolic link, or it's
0910 // empty, we want to try to delete the link before we try
0911 // anything
0912 boolean deleted = file.delete();
0913 if (!deleted) {
0914 // deleting the file failed, so maybe it's a non-empty
0915 // directory
0916 if (file.isDirectory()) {
0917 deleted = deleteDir(file, true);
0918 }
0919
0920 // otherwise, there's nothing else we can do
0921 }
0922 success = success && deleted;
0923 }
0924 }
0925
0926 return success;
0927 }
0928
0929 /**
0930 * Determines whether the specified file is a symbolic link rather than an actual file.
0931 * See {@link
0932 * https://svn.apache.org/repos/asf/commons/proper/io/trunk/src/main/java/org/apache/commons/io/FileUtils.java}.
0933 * @param file File to check.
0934 * @return Is the file is a symbolic link?
0935 * @throws IOException IO error while checking the file.
0936 */
0937 public static boolean isSymbolicLink(final File file) throws IOException {
0938 if (file == null) {
0939 throw new NullPointerException("File must not be null");
0940 }
0941 // is windows file system in use?
0942 if (File.separatorChar == '\\') {
0943 // we have no symbolic links
0944 return false;
0945 }
0946 File fileInCanonicalDir = null;
0947 if (file.getParent() == null) {
0948 fileInCanonicalDir = file;
0949 } else {
0950 File canonicalDir = file.getParentFile().getCanonicalFile();
0951 fileInCanonicalDir = new File(canonicalDir, file.getName());
0952 }
0953 if (fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) {
0954 return false;
0955 }
0956 return true;
0957 }
0958
0959 /**
0960 * Print current system properties to System.out.
0961 */
0962 public static void printAllSystemProperties() {
0963 Properties sysprops = System.getProperties();
0964 for (Enumeration e = sysprops.propertyNames(); e.hasMoreElements(); ) {
0965 String key = (String) e.nextElement();
0966 String value = sysprops.getProperty(key);
0967 System.out.println(key + "=" + value);
0968 }
0969 }
0970
0971 /**
0972 * Get home directory of user.
0973 *
0974 * @return Home directory of user.
0975 */
0976 public static File getUserHomeDirectory() {
0977 return new File((String) System.getProperties().get("user.home"));
0978 }
0979
0980 /**
0981 * Creates necessary parent directories for a file.
0982 *
0983 * @param file File.
0984 * @throws IOException Creation failed.
0985 */
0986 public static void createNecessaryDirectories(final File file) throws IOException {
0987 if (file != null && file.getParentFile() != null) {
0988 file.getParentFile().mkdirs();
0989 if (!file.getParentFile().exists()) {
0990 throw new IOException("directory creation failed: " + file.getParent());
0991 }
0992 }
0993 }
0994
0995 /**
0996 * Create relative address from <code>origin</code> to <code>next</code>.
0997 * The resulting file path has "/" as directory name separator.
0998 * If the resulting file path is the same as origin specifies, we return "".
0999 * Otherwise the result will always have an "/" as last character.
1000 *
1001 * @param origin This is the original location. Must be a directory.
1002 * @param next This should be the next location. Must also be a directory.
1003 * @return Relative (or if necessary absolute) file path.
1004 */
1005 public static final String createRelativePath(final File origin, final File next) {
1006 if (origin.equals(next)) {
1007 return "";
1008 }
1009 final Path org = new Path(origin.getPath().replace(File.separatorChar, '/'), "");
1010 final Path ne = new Path(next.getPath().replace(File.separatorChar, '/'), "");
1011 return org.createRelative(ne.toString()).toString();
1012 }
1013
1014 /**
1015 * Waits until a '\n' was read from System.in.
1016 */
1017 public static void waitln() {
1018 System.out.println("\n..press <return> to continue");
1019 try {
1020 (new java.io.BufferedReader(new java.io.InputStreamReader(
1021 System.in))).readLine();
1022 } catch (IOException e) {
1023 // ignore
1024 }
1025 }
1026
1027 /**
1028 * Closes input stream without exception.
1029 *
1030 * @param in Input stream, maybe <code>null</code>.
1031 */
1032 public static void close(final InputStream in) {
1033 if (in != null) {
1034 try {
1035 in.close();
1036 } catch (Exception e) {
1037 // ignore
1038 }
1039 }
1040 }
1041
1042 /**
1043 * Closes writer without exception.
1044 *
1045 * @param writer Writer, maybe <code>null</code>.
1046 */
1047 public static void close(final Writer writer) {
1048 if (writer != null) {
1049 try {
1050 writer.close();
1051 } catch (Exception e) {
1052 // ignore
1053 }
1054 }
1055 }
1056
1057 /**
1058 * Closes out stream without exception.
1059 *
1060 * @param out Output stream, maybe <code>null</code>.
1061 */
1062 public static void close(final OutputStream out) {
1063 if (out != null) {
1064 try {
1065 out.close();
1066 } catch (Exception e) {
1067 // ignore
1068 }
1069 }
1070 }
1071
1072 /**
1073 * Closes input reader without exception.
1074 *
1075 * @param reader Reader, maybe <code>null</code>.
1076 */
1077 public static void close(final Reader reader) {
1078 if (reader != null) {
1079 try {
1080 reader.close();
1081 } catch (Exception e) {
1082 // ignore
1083 }
1084 }
1085 }
1086
1087 /**
1088 * Get start directory for application. Within the start directory all newly created data is
1089 * stored in. If this is no Java Webstart version the result is
1090 * <code>new File(".")</code>. Otherwise the start directory is the subdirectory
1091 * "." concatenated <code>application</code> within <code>user.home</code>.
1092 * If a system property <code>application + ".startDirectory"</code> is defined we take this
1093 * as the start directory.
1094 *
1095 * @param application Application name, used for Java Webstart version. Should
1096 * be written in lowercase letters. A "." is automatically appended at
1097 * the beginning.
1098 * @return Start directory for application.
1099 */
1100 public static final File getStartDirectory(final String application) {
1101 final File startDirectory;
1102 final String property = System.getProperty(application + ".startDirectory");
1103 if (property != null && property.length() > 0) {
1104 startDirectory = new File(property);
1105 } else if (isWebStarted()) {
1106 startDirectory = new File(getUserHomeDirectory(), "." + application);
1107 } else {
1108 startDirectory = new File(".");
1109 }
1110 return startDirectory;
1111 }
1112
1113 /**
1114 * Was the application started by Java Webstart?
1115 *
1116 * @return Was the application started by Java Webstart.
1117 */
1118 public static final boolean isWebStarted() {
1119 final String webStart = (String) System.getProperties().get("javawebstart.version");
1120 return webStart != null;
1121 }
1122
1123 /**
1124 * Loads a property file from given URL.
1125 *
1126 * @param url URL to load properties from. Must not be <code>null</code>.
1127 * @return Loaded properties.
1128 * @throws IOException Reading error.
1129 */
1130 public static Properties loadProperties(final URL url)
1131 throws IOException {
1132 Properties newprops = new Properties();
1133 InputStream in = null;
1134 try {
1135 in = url.openStream();
1136 newprops.load(in);
1137 } finally {
1138 close(in);
1139 }
1140 return newprops;
1141 }
1142
1143 /**
1144 * Sleep my little class.
1145 *
1146 * @param ms Milliseconds to wait.
1147 */
1148 public static void sleep(final int ms) {
1149 final Object monitor = new Object();
1150 synchronized (monitor) {
1151 try {
1152 monitor.wait(ms);
1153 } catch (InterruptedException e) {
1154 }
1155 }
1156 }
1157
1158 /**
1159 * Get currently running java version and subversion numbers. This is the running JRE version.
1160 * If no version could be identified <code>null</code> is returned.
1161 *
1162 * @return Array of version and subversion numbers.
1163 */
1164 public static int[] getJavaVersion() {
1165 final String version = System.getProperty("java.version");
1166 final List numbers = new ArrayList();
1167 final StringTokenizer tokenizer = new StringTokenizer(version, ".");
1168 while (tokenizer.hasMoreElements()) {
1169 String sub = tokenizer.nextToken();
1170 for (int i = 0; i < sub.length(); i++) {
1171 if (!Character.isDigit(sub.charAt(i))) {
1172 sub = sub.substring(0, i);
1173 break;
1174 }
1175 }
1176 try {
1177 numbers.add(new Integer(Integer.parseInt(sub)));
1178 } catch (Exception e) {
1179 e.printStackTrace();
1180 break;
1181 }
1182 }
1183 if (numbers.size() == 0) {
1184 return null;
1185 }
1186 final int[] result = new int[numbers.size()];
1187 for (int i = 0; i < numbers.size(); i++) {
1188 result[i] = ((Integer) numbers.get(i)).intValue();
1189 }
1190 return result;
1191 }
1192
1193 /**
1194 * Get key sorted list of all System Properties.
1195 *
1196 * @return Array with the two columns key and value.
1197 */
1198 public static String[][] getSortedSystemProperties() {
1199 final Map map = new TreeMap(System.getProperties());
1200 String[][] rowData = new String[map.size()][2];
1201 int rowNum = 0;
1202 final Iterator iterator = map.entrySet().iterator();
1203 while (iterator.hasNext()) {
1204 Map.Entry entry = (Map.Entry) iterator.next();
1205 rowData[rowNum][0] = (String) entry.getKey();
1206 rowData[rowNum][1] = (String) entry.getValue();
1207 rowNum++;
1208 }
1209 return rowData;
1210 }
1211
1212 }
|