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