001package arcommon; 002 003import java.io.BufferedInputStream; 004import java.io.BufferedOutputStream; 005import java.io.BufferedReader; 006import java.io.BufferedWriter; 007import java.io.File; 008import java.io.FileFilter; 009import java.io.FileInputStream; 010import java.io.FileNotFoundException; 011import java.io.FileOutputStream; 012import java.io.FileReader; 013import java.io.FileWriter; 014import java.io.FilenameFilter; 015import java.io.IOException; 016import java.io.InputStreamReader; 017import java.io.OutputStreamWriter; 018import java.io.RandomAccessFile; 019import java.io.UnsupportedEncodingException; 020import java.nio.channels.FileChannel; 021import java.nio.channels.FileLock; 022import java.nio.channels.OverlappingFileLockException; 023import java.nio.file.Files; 024import java.nio.file.Path; 025import java.nio.file.Paths; 026import java.util.ArrayList; 027import java.util.Arrays; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.Comparator; 031import java.util.Enumeration; 032import java.util.Iterator; 033import java.util.List; 034import java.util.Properties; 035 036import arcommon.Util.OsType; 037import arcommon.progress.ProgressState; 038import arcommon.progress.ProgressThreadData; 039import arcommon.ui.other.GUIUtil; 040/** 041 * A collection of miscellaneous file IO methods. 042 * <br> 043 * Terminology in naming is as follows:<br> 044 * Directory: The directory with its content (Name, number of files, last modified...), but not the path to the directory. Typically not a {@link java.lang.String}, but the directory name (without its path) is a {@link java.lang.String}.<br> 045 * Path: The path to a directory. A {@link java.lang.String} containing a list of directory name separated by {@link java.io.File#separator}. Must typically end with a {@link java.io.File#separator}.<br> 046 * File name: A {@link java.lang.String} containing the name of a file. May contain the path to the directory, where the file is placed. Must not end with a {@link java.io.File#separator}.<br> 047 */ 048public class FileUtil { 049 public static final int MAXIMUM_WINDOWS_FILE_NAME_LENGTH = 259; 050 051 public static final String WINDOWS_TEMP_PATH = "C:\\temp\\"; 052 public static final String LINUX_TEMP_PATH = "/tmp/"; 053 public static final String MAC_TEMP_PATH = "/tmp/"; 054 055 public static boolean warnIfBomHeaderRemoved = true; 056 057 public static String calculateDriveName(String fileName) { 058 if (!Util.isWindowsOS()) { 059 throw new RuntimeException("Unsupported operating system"); 060 } 061 if (fileName == null) { 062 return null; 063 } 064 fileName = calculateAbsoluteFileName(fileName); 065 int index = fileName.indexOf(File.separator); 066 if (index == -1) { 067 return fileName; 068 } 069 String driveName = fileName.substring(0, index); 070 if (!StringUtil.doesStringMatchRegExp(driveName, "[A-Z]\\:")) { 071 throw new RuntimeException("!StringUtil.doesStringMatchRegExp(driveName, \"[A-Z]\\:\") " + driveName); 072 } 073 return driveName; 074 } 075 076 public static String calculatePath(String fileName) { 077 if (fileName.endsWith(File.separator)) { 078 return fileName; 079 } 080 File file = new File(fileName); 081 File parentFile = file.getParentFile(); 082 if (parentFile == null) { 083 return ""; 084 } 085 String result = parentFile.getPath(); 086 if (!result.endsWith(File.separator)) { 087 result += File.separator; 088 } 089 return result; 090 } 091 092 public static String calculatePathNoIO(String fileName) { 093 if (fileName.endsWith(File.separator)) { 094 return fileName; 095 } 096 int lastIndex = fileName.lastIndexOf(File.separator, fileName.length() - 2); 097 if (lastIndex == - 1) { 098 return ""; 099 } 100 return fileName.substring(0, lastIndex + 1); 101 } 102 103 public static String addDirectorySeparatorToPath(String path) { 104 if (path.length() > 0 && !path.endsWith(File.separator)) { 105 path += File.separator; 106 } 107 return path; 108 } 109 110 public static String calculateExtension(String fileName) { 111 return calculateExtension(fileName, true); 112 } 113 114 public static String calculateExtension(String fileName, boolean withDot) { 115 String onlyFileName = calculateFileNameNoIO(fileName); 116 int position = onlyFileName.lastIndexOf('.'); 117 if (position == -1) { 118 return ""; 119 } 120 if (!withDot) { 121 return onlyFileName.substring(position + 1); 122 } 123 return onlyFileName.substring(position); 124 } 125 126 public static String calculateFileName(String fileName) { 127 if (fileName.endsWith(File.separator)) { 128 return ""; 129 } 130 File file = new File(fileName); 131 String result = file.getName(); 132 return result; 133 } 134 135 public static String calculateFileNameNoIO(String fileName) { 136 if (fileName.endsWith(File.separator)) { 137 return ""; 138 } 139 int index = fileName.lastIndexOf(File.separator); 140 if (index == -1) { 141 return fileName; 142 } 143 return fileName.substring(index + 1); 144 } 145 146 public static String calculateFileNameNoExtension(String fileName) { 147 if (fileName.endsWith(File.separator)) { 148 return ""; 149 } 150 File file = new File(fileName); 151 String result = file.getName(); 152 int index = result.lastIndexOf('.'); 153 if (index != -1) { 154 result = result.substring(0, index); 155 } 156 return result; 157 } 158 159 public static String calculateLastDirectoryName(String fileName) { 160 File file = new File(fileName); 161 File directory; 162 if (file.exists() && !file.isDirectory()) { 163 directory = file.getParentFile(); 164 } else { 165 directory = file; 166 } 167 if (directory == null) { 168 return null; 169 } 170 String result = directory.getName(); 171 return result; 172 } 173 174 public static String calculateLastDirectoryNameNoIO(String fileName) { 175 String path = calculatePathNoIO(fileName); 176 int lastIndex = path.lastIndexOf(File.separator, path.length() - 2); 177 if (lastIndex == - 1) { 178 return ""; 179 } 180 181 return path.substring(lastIndex + 1, path.length() - 1); 182 } 183 184 public static String calculateParentPathFromPath(String path) { 185 validatePath(path); 186 File file = new File(path); 187 file = file.getParentFile(); 188 if (file == null) { 189 return ""; 190 } 191 String result = file.toString(); 192 if (!result.endsWith(File.separator)) { 193 result += File.separator; 194 } 195 return result; 196 } 197 198 public static List<String> calculateAllDirectoryNames(String fileName) { 199 File file = new File(fileName); 200 File directory; 201 if (!file.isDirectory() && file.exists()) { 202 directory = file.getParentFile(); 203 } else { 204 directory = file; 205 } 206 207 ArrayList<String> result = new ArrayList<String>(); 208 while (directory != null) { 209 String directoryName = directory.getName(); 210 if (directoryName.equals("")) { 211 directoryName = directory.toString(); 212 } else { 213 directoryName += File.separator; 214 } 215 if (result.size() == 0) { 216 result.add(directoryName); 217 } else { 218 result.add(0, directoryName); 219 } 220 directory = directory.getParentFile(); 221 } 222 223 return result; 224 } 225 226 /** Returns the absolute path name of path relative to current directory. 227 * <br> 228 * See {@link #calculateAbsolutePath(String, String)} for details.<br> 229 */ 230 public static String calculateAbsolutePath(String path) { 231 return calculateAbsolutePath(null, path); 232 } 233 234 /** Returns the absolute path name of path relative to basePath. 235 * <br> 236 * See {@link #calculateAbsoluteFileName(String, String)} for details.<br> 237 */ 238 public static String calculateAbsolutePath(String basePath, String path) { 239 path = calculateAbsoluteFileName(basePath, path); 240 if (!path.endsWith(File.separator)) { 241 path += File.separator; 242 } 243 return path; 244 } 245 246 /** Returns the absolute file name of fileName relative to current directory. 247 * <br> 248 * See {@link #calculateAbsoluteFileName(String, String)} for details.<br> 249 */ 250 public static String calculateAbsoluteFileName(String fileName) { 251 return calculateAbsoluteFileName(null, fileName); 252 } 253 254 /** Returns the absolute file name of fileName relative to basePath. 255 * <br> 256 * The absolute file name is calculated using the {@link java.io.File#getCanonicalFile()} method.<br> 257 * See {@link #calculateAbsoluteFileNameLocal(String)} for details.<br> 258 * If basePath is null the current directory is use as base.<br> 259 * All File.separator + File.separator in fileName will be replaced with File.separator ("//" -> "/" and "\" -> "\"). 260 */ 261 public static String calculateAbsoluteFileName(String basePath, String fileName) { 262 File file = new File(fileName); 263 if (file.isAbsolute()) { 264 // The file name is absolute (Starts with a File.separator), but may contain ".." or File.separator + File.separator. 265 if (fileName.contains("..") || fileName.contains(File.separator + File.separator)) { 266 return calculateAbsoluteFileNameLocal(fileName); 267 } 268 return fileName; 269 } 270 271 if (basePath == null || basePath.length() == 0) { 272 basePath = currentPath(); 273 } 274 if (basePath.endsWith(File.separator) && fileName.startsWith(File.separator)) { 275 fileName = fileName.substring(1); 276 } 277 if (!basePath.endsWith(File.separator) && !fileName.startsWith(File.separator)) { 278 basePath += File.separator; 279 } 280 281 return calculateAbsoluteFileNameLocal(basePath + fileName); 282 } 283 284 private static String calculateAbsoluteFileNameLocal(String fileName) { 285 while (fileName.contains(File.separator + File.separator)) { 286 fileName = StringUtil.replace(fileName, File.separator + File.separator, File.separator); 287 } 288 File file = new File(fileName); 289 try { 290 file = file.getCanonicalFile(); 291 } catch (IOException e) { 292 throw new RuntimeException(e); 293 } 294 return file.toString(); 295 } 296 297 public static boolean isAbsolute(String fileName) { 298 File file = new File(fileName); 299 return file.isAbsolute(); 300 } 301 302 public static String convertTo8Dot3(String fileName) { 303 String[] strings = fileName.split("\\\\"); // Should be File.separator, but it don't work for \\. Would probably work for /. 304 String result = ""; 305 for (int i = 0; i < strings.length; i++) { 306 if (i > 0) { 307 result += File.separator; 308 } 309 result += convertTo8Dot3Local(strings[i]); 310 } 311 return result; 312 } 313 314 private static String convertTo8Dot3Local(String fileName) { 315 if (fileName.indexOf(' ') == -1) { 316 return fileName; 317 } 318 fileName = fileName.replaceAll(" ", ""); 319 int index = fileName.indexOf('.'); 320 String extension = ""; 321 if (index != -1) { 322 extension = fileName.substring(index); 323 if (extension.length() > 3 + 1) { 324 extension = extension.substring(0, 3 + 1); 325 } 326 fileName = fileName.substring(0, index); 327 } 328 if (fileName.length() > 6) { 329 fileName = fileName.substring(0, 6); 330 } 331 fileName += "~1" + extension; // MEGA HACK 332 return fileName; 333 } 334 335 private static boolean isPathEndingValid(String path) { 336 return path.endsWith(File.separator); 337 } 338 339 private static void validatePath(String path) { 340 if (!isPathValid(path)) { 341 throw new RuntimeException("Path \"" + path + "\" is not valid"); 342 } 343 } 344 345 public static boolean isPathValid(String path) { 346 if (!isPathEndingValid(path)) { 347 return false; 348 } 349 350 return isPathOrFileNameValid(path); 351 } 352 353 private static boolean isFileNameEndingValid(String fileName) { 354 return !fileName.endsWith(File.separator); 355 } 356 357 private static void validateFileName(String fileName) { 358 if (!isFileNameValid(fileName)) { 359 throw new RuntimeException("File name \"" + fileName + "\" is not valid"); 360 } 361 } 362 363 public static boolean isFileNameValid(String fileName) { 364 if (!isFileNameEndingValid(fileName)) { 365 return false; 366 } 367 368 return isPathOrFileNameValid(fileName); 369 } 370 371 private static boolean isPathOrFileNameValid(String fileName) { 372 if (Util.isWindowsOS()) { 373 return isWindowsPathOrFileNameValid(fileName); 374 } 375 376 if (Util.isLinuxOS()) { 377 return isLinuxPathOrFileNameValid(fileName); 378 } 379 380 return true; 381 } 382 383 public static boolean isWindowsFileNameValid(String fileName) { 384 if (!isFileNameEndingValid(fileName)) { 385 return false; 386 } 387 388 return isWindowsPathOrFileNameValid(fileName); 389 } 390 391 private static boolean isWindowsPathOrFileNameValid(String fileName) { 392 if (fileName.endsWith(" ")) { // File name must not end with a space 393 return false; 394 } 395 396 if (fileName.contains(" \\")) { // Directory name must not end with a space 397 return false; 398 } 399 400 if (fileName.contains("\\\\")) { // Directory name must not be empty 401 return false; 402 } 403 404 if (fileName.contains("\\.\\")) { // Current directory is only allowed in the start of the path 405 return false; 406 } 407 408 boolean result = StringUtil.doesStringMatchRegExp(fileName, "([A-Z]:){0,1}[a-zA-Z0-9 \\\\\\+-.,;!_=~&'%$#@æåøÆÅØüç(){}\\[\\]]*"); 409 if (!result) { 410 return false; 411 } 412 413 if (isWindowsFileNameToLong(fileName)) { 414 return false; 415 } 416 417 return true; 418 } 419 420 public static boolean isLinuxFileNameValid(String fileName) { 421 if (!isFileNameEndingValid(fileName)) { 422 return false; 423 } 424 425 return isLinuxPathOrFileNameValid(fileName); 426 } 427 428 private static boolean isLinuxPathOrFileNameValid(String fileName) { 429 if (fileName.contains("//")) { // Directory name must not be empty 430 return false; 431 } 432 433 if (fileName.contains("/./")) { // Current directory is only allowed in the start of the path 434 return false; 435 } 436 437 return true; 438 } 439 440 public static boolean isFileNameToLong(String fileName) { 441 return Util.isWindowsOS() && isWindowsFileNameToLong(fileName); 442 } 443 444 public static boolean isWindowsFileNameToLong(String fileName) { 445 return fileName.length() > MAXIMUM_WINDOWS_FILE_NAME_LENGTH; 446 } 447 448 public static void checkFileNameLengthAndWarn(String fileName) { 449 if (isFileNameToLong(fileName)) { 450 GUIUtil.showWarning("The file name \n \"" + fileName + "\"\n is too long (" + fileName.length() + " > " + MAXIMUM_WINDOWS_FILE_NAME_LENGTH + ")"); 451 } 452 } 453 454 public static String replaceAllSpecialFileNameChars(String fileName) { 455 fileName = replaceSpecialFileNameAndDirectoryChars(fileName); 456 fileName = fileName.replaceAll("[^a-zA-Z0-9 \\-._]", "_"); 457 return fileName; 458 } 459 460 public static String replaceSpecialDirectoryChars(String fileName) { 461 fileName = fileName.replace("..", "_"); 462 fileName = fileName.replace('\\', '_'); 463 fileName = fileName.replace('/', '_'); 464 return fileName; 465 } 466 467 public static String replaceSpecialFileNameAndDirectoryChars(String fileName) { 468 fileName = replaceSpecialDirectoryChars(fileName); 469 fileName = replaceSpecialFullFileNameChars(fileName); 470 return fileName; 471 } 472 473 public static String replaceSpecialFullFileNameChars(String fileName) { 474 fileName = fileName.replace('$', '_'); 475 fileName = fileName.replace('?', '_'); 476 fileName = fileName.replace('<', '_'); 477 fileName = fileName.replace('>', '_'); 478 fileName = fileName.replace(';', '_'); 479 fileName = fileName.replace('\"', '_'); 480 fileName = fileName.replace('*', '_'); 481 fileName = fileName.replace('%', '_'); 482 return fileName; 483 } 484 485 public static boolean isDirectory(String fileName) { 486 if (!exists(fileName)) { 487 throw new RuntimeException("!exists(fileName): " + fileName); 488 } 489 return new File(fileName).isDirectory(); 490 } 491 492 public static boolean isDirectoryCaseSensitive(String path) { 493 if (Util.isWindowsOS()) { 494 return false; 495 } 496 497 if (!exists(path)) { 498 throw new RuntimeException("Directory \"" + path + "\" doesn't exist"); 499 } 500 if (!isDirectory(path)) { 501 throw new RuntimeException("Path \"" + path + "\" is not a directory"); 502 } 503 504 if (!path.endsWith(File.separator)) { 505 path = path + File.separator; 506 } 507 508 String fileName = createTempFile(path, DEFAULT_TEMP_FILE_PREFIX + "FileUtil - isDirectoryCaseSensitive - ", ".txt"); 509 510 boolean exists = exists(fileName); 511 if (!exists) { 512 throw new RuntimeException("Internal error " + fileName); 513 } 514 515 String fileNamePart = calculateFileName(fileName); 516 String fileNameLowerCase = path + fileNamePart.toLowerCase(); 517 boolean lowerCaseExists = exists(fileNameLowerCase); 518 519 delete(fileName); 520 521 return !lowerCaseExists; 522 } 523 524 public static boolean canFilesInDirectoryBeMarkedExecutable(String path) { 525 if (Util.isWindowsOS()) { 526 return false; 527 } 528 529 if (!exists(path)) { 530 throw new RuntimeException("Directory \"" + path + "\" doesn't exist"); 531 } 532 if (!isDirectory(path)) { 533 throw new RuntimeException("Path \"" + path + "\" is not a directory"); 534 } 535 536 if (!path.endsWith(File.separator)) { 537 path = path + File.separator; 538 } 539 540 String fileName = createTempFile(path, DEFAULT_TEMP_FILE_PREFIX + "FileUtil - canFilesInDirectoryBeMarkedExecutable - ", ".txt"); 541 542 setExecutable(fileName, true); 543 544 boolean canExecute = getExecutable(fileName); 545 546 delete(fileName); 547 548 return canExecute; 549 } 550 551 /** 552 * This method will return the file system of path. 553 * <br> 554 * NOTE: This method will return strings like these on Linux: "ext4", "fuseblk" (NTFS), "iso9660" (CD image on USB) and "vfat" (FAT32).<br> 555 * Code copied from <a href="https://stackoverflow.com/questions/16660918/determine-filesystem-type-of-given-file-in-java">https://stackoverflow.com/questions/16660918/determine-filesystem-type-of-given-file-in-java</a><br> 556 * and modified 557 * @see #calculateFileSystemType(String) see calculateFileSystemType for a method that will return kind of the same information. 558 */ 559/* public static String getFileSystemString(String path) { 560 try { 561 File pathFile = new File(path); 562 Path pathPath = Path.of(pathFile.getPath()); // Since 11 563 return Files.getFileStore(pathPath).type(); 564 } catch (IOException e) { 565 throw new RuntimeException(e); 566 } 567 }*/ 568 569 public static enum FILE_SYSTEM {EXT4, NTFS, FAT32, UNKNOWN}; 570 571 /** 572 * This method will calculate the file system of path (in a very hacky way) and return it. 573 * <br> 574 * NOTE: This method requires that the path is writable. If it is not writable, UNKNOWN is returned.<br> 575 * NOTE: This method is slow as it creates and deletes files in path.<br> 576 * NOTE: This method has NOT been tested on Mac at all. 577 * See the uncomment method getFileSystemString(String) above for a method that will return kind of the same information. 578 */ 579 public static FILE_SYSTEM calculateFileSystemType(String path) { 580 boolean writeAccess = FileUtil.checkWriteAccess(path); 581 if (!writeAccess) { 582 System.out.println("No write access to \"" + path + "\" => File system can't be determinant"); 583 return FILE_SYSTEM.UNKNOWN; 584 } 585 586 String existingParent = FileUtil.findExistingParent(path); 587 if (Util.isWindowsOS()) { 588 String fileName = FileUtil.createTempFile(existingParent, FileUtil.DEFAULT_TEMP_FILE_PREFIX + "FileUtil - getFileSystem - ", ".bat"); 589 String outputFileNameStart = "Data"; 590 String outputFileNameEnd = ":1234.txt"; // Note: The ':' is the NTFS data stream separator char (not "drive letter" "path" separator). 591 String outputFileName = outputFileNameStart + outputFileNameEnd; 592 String fullOutputFileName = existingParent + outputFileName; 593 FileUtil.writeFile(fileName, "echo This is test data > " + outputFileName, false, "Cp1252"); 594 int exitCode = ProcessUtil.executeCommandNoInputNoOutput(fileName, new File(existingParent)); 595 FileUtil.delete(fileName); 596 boolean exists = FileUtil.exists(fullOutputFileName); 597 if (exists && exitCode == 0) { 598 FileUtil.delete(fullOutputFileName); 599 exists = FileUtil.exists(fullOutputFileName); 600 if (exists) { 601 throw new RuntimeException("exists " + fullOutputFileName); 602 } 603 String partlyOutputFileName = existingParent + outputFileNameStart; 604 FileUtil.delete(partlyOutputFileName); 605 exists = FileUtil.exists(partlyOutputFileName); 606 if (exists) { 607 throw new RuntimeException("exists " + fullOutputFileName); 608 } 609 return FILE_SYSTEM.NTFS; 610 } 611 612 return FILE_SYSTEM.FAT32; 613 } 614 615 try { 616 // Files containing a ':' can only be created on EXT4 on Linux. 617 String fileName = FileUtil.createTempFile(existingParent, FileUtil.DEFAULT_TEMP_FILE_PREFIX + "FileUtil - getFileSystem - : - ", ".txt"); 618 FileUtil.delete(fileName); 619 return FILE_SYSTEM.EXT4; 620 } catch (Exception e) { 621 ; // Exception ignored 622 } 623 624 boolean directoryCaseSensitive = FileUtil.isDirectoryCaseSensitive(existingParent); 625 if (directoryCaseSensitive) { 626 // NTFS is (wrongly) case sensitive on Linux. 627 return FILE_SYSTEM.NTFS; 628 } 629 630 return FILE_SYSTEM.FAT32; 631 } 632 633 public static boolean exists(String fileName) { 634 return new File(fileName).exists(); 635 } 636 637 public static long lastModified(String fileName) { 638 if (!exists(fileName)) { 639 throw new RuntimeException("!exists(fileName): " + fileName); 640 } 641 return new File(fileName).lastModified(); 642 } 643 644 public static void setLastModified(String fileName, long lastModified) { 645 if (!exists(fileName)) { 646 throw new RuntimeException("!exists(fileName): " + fileName); 647 } 648 File file = new File(fileName); 649 file.setLastModified(lastModified); 650 } 651 652 public static long size(String fileName) { 653 if (!exists(fileName)) { 654 throw new RuntimeException("!exists(fileName): " + fileName); 655 } 656 if (isDirectory(fileName)) { 657 throw new RuntimeException("isDirectory(fileName): " + fileName); 658 } 659 return new File(fileName).length(); 660 } 661 662 public static boolean checkForExistsAndWarm(String fileName) { 663 if (exists(fileName)) { 664 if (isDirectory(fileName)) { 665 GUIUtil.showErrorMessage("\"" + fileName + "\" is a directory"); 666 return false; 667 } 668 669 GUIUtil.YesNoDialogAnswer answer = GUIUtil.showYesNoCancelDialog("File \"" + fileName + "\" already exists. Should it be overwritten?"); 670 switch (answer) { 671 case YES : 672 ; 673 break; 674 case NO : 675 return false; 676// break; 677 case CANCEL : 678 return false; 679// break; 680 default : 681 throw new RuntimeException("Unknown answer " + answer); 682// break; 683 } 684 } 685 686 return true; 687 } 688 689 public static void mkdirs(String path) { 690 mkdirs(new File(path)); 691 } 692 693 public static void mkdirs(File path) { 694 mkdirs(path, true); 695 } 696 697 public static boolean mkdirs(String path, boolean throwOnFail) { 698 return mkdirs(new File(path), throwOnFail); 699 } 700 701 public static synchronized boolean mkdirs(File path, boolean throwOnFail) { 702 if (path == null) { 703 throw new NullPointerException("path == null"); 704 } 705 if (path.toString().length() == 0) { 706 throw new RuntimeException("path.toString().length() == 0"); 707 } 708 if (path.exists()) { 709 return true; 710 } 711 path.mkdirs(); // This is not thread safe. Might return false, when an another thread has created the path. 712 // Solved by using "synchronized" and the extra "path.exists()" check after "mkdirs()" 713 boolean ok = path.exists(); 714 if (!ok && throwOnFail) { 715 throw new RuntimeException("mkdirs() failed \"" + path + "\""); 716 } 717 return ok; 718 } 719 720 public static void mkdirsAndFile(String fileName) { 721 File toFile = new File(fileName); 722 if (toFile.exists()) { 723 return ; 724 } 725 File parentFile = toFile.getParentFile(); 726 mkdirs(parentFile); 727 try { 728 if (!toFile.createNewFile()) { 729 throw new RuntimeException("Creation of file failed \"" + fileName + "\""); 730 } 731 } catch (IOException e) { 732 throw new RuntimeException(e); 733 } 734 } 735 736 public static String readFile(String fileName) { 737 return readFile(fileName, null); 738 } 739 740 public static String readFile(String fileName, String encoding) { 741 return readFile(fileName, encoding, -1); 742 } 743 744 public static final int READ_NO_MAXIMUM_NUMBER_OF_BYTES = -1; 745 746 public static String readFile(String fileName, String encoding, int maximumNumberOfBytes) { 747 BufferedReader bufferedReader = null; 748 try { 749 bufferedReader = createBufferedReader(fileName, encoding); 750 751 ProgressState progressState = ProgressThreadData.createProgressState(); 752 if (progressState != null) { 753 progressState.setName("Reading text in file " + fileName); 754 long size = size(fileName); 755 progressState.setMaximum(maximumNumberOfBytes == READ_NO_MAXIMUM_NUMBER_OF_BYTES ? (int)(size) : maximumNumberOfBytes); 756 progressState.setUseUnits(true); 757 } 758 759 char[] buffer = new char[maximumNumberOfBytes == READ_NO_MAXIMUM_NUMBER_OF_BYTES ? 100000 : maximumNumberOfBytes]; 760 StringBuilder stringBuilder = new StringBuilder(); 761 while (bufferedReader.ready()) { 762 int count = bufferedReader.read(buffer); 763 if (progressState != null) { 764 progressState.setCurrent(progressState.getCurrent() + count); 765 } 766 stringBuilder.append(new String(buffer, 0, count)); 767 if (maximumNumberOfBytes != - 1 && stringBuilder.length() >= maximumNumberOfBytes) { 768 break; 769 } 770 } 771 772 ProgressThreadData.disposeProgressState(progressState); 773 bufferedReader.close(); 774 775 String result = stringBuilder.toString(); 776 result = removeUtf8Bom(fileName, encoding, result, warnIfBomHeaderRemoved, true); 777 if (maximumNumberOfBytes != READ_NO_MAXIMUM_NUMBER_OF_BYTES && stringBuilder.length() > maximumNumberOfBytes) { 778 return result.substring(0, maximumNumberOfBytes); 779 } 780 return result; 781 } catch (Exception e) { 782 if (bufferedReader != null) { 783 try { 784 bufferedReader.close(); 785 } catch (IOException e1) { 786 throw new RuntimeException(e1); 787 } 788 } 789 System.out.println(e.getMessage()); 790 System.out.println("fileName: " + fileName); 791 throw new RuntimeException(e); 792 } 793 } 794 795 public static BufferedReader createBufferedReader(String fileName, String encoding) { 796 try { 797 BufferedReader in; 798 if (encoding == null) { 799 in = new BufferedReader(new FileReader(fileName)); 800 } else { 801 in = new BufferedReader(new InputStreamReader(new FileInputStream(new File(fileName)), encoding)); 802 } 803 return in; 804 } catch (IOException e) { 805 throw new RuntimeException(e); 806 } 807 } 808 809 public static String readFirstLineInFile(String fileName) { 810 return readFirstLineInFile(fileName, null); 811 } 812 813 public static String readFirstLineInFile(String fileName, String encoding) { 814 BufferedReader in = null; 815 try { 816 in = createBufferedReader(fileName, encoding); 817 String line = ""; 818 if (in.ready()) { 819 line = in.readLine(); 820 line = removeUtf8Bom(fileName, encoding, line, warnIfBomHeaderRemoved, true); 821 } 822 in.close(); 823 return line; 824 } catch (Exception e) { 825 if (in != null) { 826 try { 827 in.close(); 828 } catch (IOException e1) { 829 throw new RuntimeException(e1); 830 } 831 } 832 System.out.println(e.getMessage()); 833 System.out.println("fileName: " + fileName); 834 throw new RuntimeException(e); 835 } 836 } 837 838 public static interface LineReadInterface { 839 public boolean lineRead(String line); 840 } 841 842 public static List<String> readLinesInFile(String fileName) { 843 return readLinesInFile(fileName, (String)null); 844 } 845 846 public static List<String> readLinesInFile(String fileName, String encoding) { 847 final ArrayList<String> result = new ArrayList<String>(); 848 readLinesInFile(fileName, encoding, new LineReadInterface() { 849 public boolean lineRead(String line) { 850 result.add(line); 851 return true; 852 } 853 }); 854 return result; 855 } 856 857 public static void readLinesInFile(String fileName, LineReadInterface lineReadInterface) { 858 readLinesInFile(fileName, null, lineReadInterface); 859 } 860 861 public static void readLinesInFile(String fileName, String encoding, LineReadInterface lineReadInterface) { 862 BufferedReader in = null; 863 try { 864 in = createBufferedReader(fileName, encoding); 865 readLinesInFile(fileName, encoding, in, lineReadInterface); 866 } catch (Exception e) { 867 if (in != null) { 868 try { 869 in.close(); 870 } catch (IOException e1) { 871 throw new RuntimeException(e1); 872 } 873 } 874 System.out.println("FileName: " + fileName); 875 throw new RuntimeException(e); 876 } 877 } 878 879 public static void readLinesInFile(String fileName, String encoding, BufferedReader in, LineReadInterface lineReadInterface) throws IOException { 880 ProgressState progressState = ProgressThreadData.createProgressState(); 881 if (progressState != null) { 882 progressState.setName("Reading lines in file " + fileName); 883 long size = size(fileName); 884 progressState.setMaximum((int)(size)); 885 progressState.setUseUnits(true); 886 } 887 888 boolean first = true; 889 while (in.ready()) { 890 String line = in.readLine(); 891 if (first) { 892 first = false; 893 line = removeUtf8Bom(fileName, encoding, line, warnIfBomHeaderRemoved, true); 894 } 895 if (progressState != null) { 896 progressState.setCurrent(progressState.getCurrent() + line.length()); 897 } 898 if (!lineReadInterface.lineRead(line)) { 899 break; 900 } 901 } 902 903 ProgressThreadData.disposeProgressState(progressState); 904 in.close(); 905 } 906 907 public static String removeUtf8Bom(String fileName, String encoding, String content, boolean warnIfRemoved, boolean exceptionOnMismatch) { 908 String tempContent = content; 909 if (tempContent.length() > 10) { 910 tempContent = tempContent.substring(0, 5); 911 } 912 913 if (encoding == null) { 914 encoding = System.getProperty("file.encoding"); 915 } 916 917 byte[] bytes; 918 try { 919 bytes = tempContent.getBytes("UTF-8"); 920 } catch (UnsupportedEncodingException e) { 921 throw new RuntimeException(e); 922 } 923 924 if (!encoding.equals("UTF-8")) { 925 bytes = readDataFromFile(fileName, 10); 926 } 927 if (bytes.length > 2 && bytes[0] == -17 && bytes[1] == -69 && bytes[2] == -65) { 928 if (encoding.equals("UTF-8")) { 929 content = content.substring(1); 930 } else if (encoding.equals("Cp1252") || encoding.equals("ISO-8859-1")) { 931 if (exceptionOnMismatch) { 932 throw new RuntimeException("The \"" + fileName + "\" file starts with a Windows UTF-8 BOM header, but the file has been requested to be read in " + encoding + " encoding"); 933 } 934 content = content.substring(3); 935 } else { 936 throw new RuntimeException("Unknown encoding " + encoding); 937 } 938 939 if (warnIfRemoved) { 940 System.out.println("WARNING: The Windows UTF-8 BOM header was removed from the \"" + fileName + "\" file!"); 941 Util.sleep(3000); 942 } 943 } 944 945 return content; 946 } 947 948 /** 949 * Read all data from fileName and return it. 950 */ 951 public static byte[] readDataFromFile(String fileName) { 952 return readDataFromFile(fileName, READ_NO_MAXIMUM_NUMBER_OF_BYTES); 953 } 954 955 /** 956 * Read data from fileName and return it. 957 * <br> 958 * If maximumNumberOfBytes is different from {@link #READ_NO_MAXIMUM_NUMBER_OF_BYTES} it is used as max read limit. 959 * See {@link #readDataFromFile(String, long, int)} for very similar code 960 */ 961 public static byte[] readDataFromFile(String fileName, int maximumNumberOfBytes) { 962 BufferedInputStream in = null; 963 try { 964 in = new BufferedInputStream(new FileInputStream(fileName)); 965 int size = (int)size(fileName); 966 if (maximumNumberOfBytes != READ_NO_MAXIMUM_NUMBER_OF_BYTES && size > maximumNumberOfBytes) { 967 size = maximumNumberOfBytes; 968 } 969 byte[] result = new byte[size]; 970 in.read(result); 971 in.close(); 972 return result; 973 } catch (Exception e) { 974 if (in != null) { 975 try { 976 in.close(); 977 } catch (IOException e1) { 978 throw new RuntimeException(e1); 979 } 980 } 981 System.out.println(e.getMessage()); 982 System.out.println("FileName: " + fileName); 983 throw new RuntimeException(e); 984 } 985 } 986 987 /** 988 * Read data from offset in fileName and return it. 989 * <br> 990 * If maximumNumberOfBytes is different from {@link #READ_NO_MAXIMUM_NUMBER_OF_BYTES} it is used as max read limit. 991 * See {@link #readDataFromFile(String, int)} for very similar code 992 */ 993 public static byte[] readDataFromFile(String fileName, long offset, int maximumNumberOfBytes) { 994 RandomAccessFile in = null; 995 try { 996 in = new RandomAccessFile(fileName, "r"); 997 in.seek(offset); 998 long size = size(fileName); 999 if (maximumNumberOfBytes != READ_NO_MAXIMUM_NUMBER_OF_BYTES && size - offset > maximumNumberOfBytes) { 1000 size = maximumNumberOfBytes; 1001 } else if (offset > 0) { 1002 size -= offset; 1003 } 1004 if (size > Integer.MAX_VALUE) { 1005 size = Integer.MAX_VALUE; 1006 } 1007 byte[] result = new byte[(int)size]; 1008 in.read(result); 1009 in.close(); 1010 return result; 1011 } catch (Exception e) { 1012 if (in != null) { 1013 try { 1014 in.close(); 1015 } catch (IOException e1) { 1016 throw new RuntimeException(e1); 1017 } 1018 } 1019 System.out.println(e.getMessage()); 1020 System.out.println("FileName: " + fileName); 1021 throw new RuntimeException(e); 1022 } 1023 } 1024 1025 public static void writeFile(String fileName, String content) { 1026 writeFile(fileName, content, false); 1027 } 1028 1029 public static void writeFile(String fileName, String content, boolean append) { 1030 writeFile(fileName, content, append, null); 1031 } 1032 1033 public static void writeFile(String fileName, String content, boolean append, String encoding) { 1034 writeFile(fileName, content, append, encoding, false); 1035 } 1036 1037 private static void writeFile(String fileName, String content, boolean append, String encoding, boolean endWithNewline) { 1038 ArrayList<String> lines = new ArrayList<String>(); 1039 if (content.length() > 0) { 1040 String[] split = content.split("\n", StringUtil.STRING_SPLIT_INCLUDING_TRAILING_EMPTY_STRINGS); 1041 for (int i = 0; i < split.length; i++) { 1042 split[i] = split[i].replaceAll("\r", ""); 1043 lines.add(split[i]); 1044 } 1045 } 1046 writeLinesToFile(fileName, lines, append, encoding, null, endWithNewline); 1047 } 1048 1049 public static void writeAppendLinesToFile(String fileName, String lines) { 1050 writeAppendLinesToFile(fileName, lines, null); 1051 } 1052 1053 public static void writeAppendLinesToFile(String fileName, String lines, String encoding) { 1054 writeFile(fileName, lines, true, encoding, true); 1055 } 1056 1057 public static enum Newline {OS_DEFAULT, WINDOWS_NEWLINE, LINUX_NEWLINE, MAC_NEWLINE}; 1058 1059 public static void writeLinesToFile(String fileName, Collection<String> lines) { 1060 writeLinesToFile(fileName, lines, false); 1061 } 1062 1063 public static void writeLinesToFile(String fileName, Collection<String> lines, boolean append) { 1064 writeLinesToFile(fileName, lines, append, null); 1065 } 1066 1067 public static void writeLinesToFile(String fileName, Collection<String> lines, boolean append, String encoding) { 1068 writeLinesToFile(fileName, lines, append, encoding, null, true); 1069 } 1070 1071 public static BufferedWriter createBufferedWriter(String fileName, boolean append, String encoding) { 1072 validateFileName(fileName); 1073 1074 BufferedWriter out; 1075 try { 1076 if (encoding == null) { 1077 out = new BufferedWriter(new FileWriter(fileName, append)); 1078 } else { 1079 out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName, append), encoding)); 1080 } 1081 } catch (IOException e) { 1082 throw new RuntimeException(e); 1083 } 1084 return out; 1085 } 1086 1087 public static void writeLinesToFile(String fileName, Collection<String> lines, boolean append, String encoding, Newline newline, boolean endWithNewline) { 1088 File toDirectory = new File(fileName).getParentFile(); 1089 if (toDirectory != null && !toDirectory.exists()) { 1090 mkdirs(toDirectory); 1091 } 1092 if (!append && exists(fileName)) { 1093 delete(fileName); 1094 } 1095 try { 1096 BufferedWriter out = createBufferedWriter(fileName, append, encoding); 1097 if (newline == null) { 1098 newline = Newline.OS_DEFAULT; 1099 } 1100 Iterator<String> i = lines.iterator(); 1101 while (i.hasNext()) { 1102 String line = i.next(); 1103 out.write(line); 1104 if (endWithNewline || i.hasNext()) { 1105 switch (newline) { 1106 case OS_DEFAULT : 1107 out.newLine(); 1108 break; 1109 case WINDOWS_NEWLINE : 1110 out.write("\r\n"); 1111 break; 1112 case LINUX_NEWLINE : 1113 out.write("\n"); 1114 break; 1115 case MAC_NEWLINE : 1116 out.write("\n"); 1117 break; 1118 default : 1119 throw new RuntimeException("Internal error"); 1120 // break; 1121 } 1122 } 1123 } 1124 out.close(); 1125 } catch (Exception e) { 1126 throw new RuntimeException(e); 1127 } 1128 } 1129 1130 public static void writeDataToFile(String fileName, byte[] data, boolean append) { 1131 validateFileName(fileName); 1132 try { 1133 File toDirectory = new File(fileName).getParentFile(); 1134 if (toDirectory != null && !toDirectory.exists()) { 1135 mkdirs(toDirectory); 1136 } 1137 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fileName, append)); 1138 out.write(data); 1139 out.close(); 1140 } catch (Exception e) { 1141 System.out.println("FileName: " + fileName); 1142 throw new RuntimeException(e); 1143 } 1144 } 1145 1146 public static final String DEFAULT_TEMP_FILE_PREFIX = "Temp file - "; 1147 1148 public static abstract class WriteUsingTempFileAction { 1149 public String createTempFile(String toFileName) { 1150 return FileUtil.createTempFile(calculatePath(toFileName), DEFAULT_TEMP_FILE_PREFIX + calculateFileNameNoExtension(toFileName) + " - ", calculateExtension(toFileName)); 1151 } 1152 1153 public void saveFile(String tempFileName, boolean append, String encoding) throws IOException { 1154 BufferedWriter out = createBufferedWriter(tempFileName, append, encoding); 1155 writeContentOfFile(out); 1156 out.close(); 1157 } 1158 1159 public abstract void writeContentOfFile(BufferedWriter out) throws IOException; 1160 1161 public boolean backupOldFile() { 1162 return true; 1163 } 1164 1165 public int getStartBackupNumber() { 1166 return 0; 1167 } 1168 1169 public String calculateBackupPath(int number, String toFileName) { 1170 return calculatePath(toFileName); 1171 } 1172 1173 public String calculateBackupFileName(int number, String toFileName) { 1174 return calculateNumberedFileName(calculateBackupPath(number, toFileName), toFileName, number); 1175 } 1176 1177 public void saveBackupNumberAndFileName(int number, String backupFileName) { 1178 ; 1179 } 1180 } 1181 1182 public static String calculateNumberedFileName(String path, String fileName, int number) { 1183 return path + calculateFileNameNoExtension(fileName) + " ~ " + number + " ~ " + calculateExtension(fileName); 1184 } 1185 1186 public static void writeUsingTempFile(String fileName, WriteUsingTempFileAction saveUsingTempFileAction) { 1187 writeUsingTempFile(fileName, null, saveUsingTempFileAction); 1188 } 1189 1190 public static void writeUsingTempFile(String fileName, String encoding, WriteUsingTempFileAction saveUsingTempFileAction) { 1191 writeUsingTempFile(fileName, false, encoding, saveUsingTempFileAction); 1192 } 1193 1194 public static void writeUsingTempFile(String fileName, boolean append, String encoding, WriteUsingTempFileAction saveUsingTempFileAction) { 1195 String tempFileName; 1196 String toFileName = fileName; 1197 boolean isTempFileUsed; 1198 if (exists(toFileName) && !append) { 1199 tempFileName = saveUsingTempFileAction.createTempFile(toFileName); 1200 isTempFileUsed = true; 1201 } else { 1202 tempFileName = toFileName; 1203 isTempFileUsed = false; 1204 } 1205 1206 try { 1207 saveUsingTempFileAction.saveFile(tempFileName, append, encoding); 1208 } catch (IOException e) { 1209 e.printStackTrace(); 1210 try { 1211 long freeSpace = getFreeSpace(tempFileName); 1212 if (freeSpace == 0) { 1213 GUIUtil.showInformation("The file was not saved, because there is no more free space on the disk!!!"); 1214 } 1215 } catch (Exception e1) { 1216 e1.printStackTrace(); 1217 } 1218 throw new RuntimeException(e); 1219 } 1220 1221 if (isTempFileUsed) { 1222 if (!saveUsingTempFileAction.backupOldFile()) { 1223 delete(toFileName); 1224 } else { 1225 int number = saveUsingTempFileAction.getStartBackupNumber(); 1226 do { 1227 String backupFileName = saveUsingTempFileAction.calculateBackupFileName(++number, fileName); 1228 if (exists(backupFileName)) { 1229 continue; 1230 } 1231 1232 String backupPath = calculatePath(backupFileName); 1233 mkdirs(backupPath); 1234 if (!rename(toFileName, backupFileName, false)) { 1235 try { 1236 long freeSpace = getFreeSpace(backupFileName); 1237 if (freeSpace == 0) { 1238 GUIUtil.showInformation("The file was not saved, because there is no more free space on the disk!!!"); 1239 } 1240 } catch (Exception e1) { 1241 e1.printStackTrace(); 1242 } 1243 throw new RuntimeException("The file \"" + toFileName + "\" could not be renamed to \"" + backupFileName + "\""); 1244 } 1245 1246 saveUsingTempFileAction.saveBackupNumberAndFileName(number, backupFileName); 1247 break; 1248 } while (true); 1249 } 1250 1251 rename(tempFileName, toFileName, true); 1252 } 1253 } 1254 1255 public static String findFileNameWithCorrectCase(String fileName) { 1256 try { 1257 String path = new File(fileName).getCanonicalPath(); 1258 if (exists(fileName) && isDirectory(fileName)) { 1259 path += File.separator; 1260 } 1261 return path; 1262 } catch (IOException e) { 1263 throw new RuntimeException(e); 1264 } 1265 } 1266 1267 public static String findFileNameWithCorrectCaseLinux(String fileName, boolean throwOnFail) { 1268 String path = calculatePath(fileName); 1269 List<String> allDirectoryNames = calculateAllDirectoryNames(path); 1270 String fileNameOnly = calculateFileName(fileName); 1271 if (fileNameOnly.length() > 0) { 1272 allDirectoryNames.add(fileNameOnly); 1273 } 1274 1275 String result = ""; 1276 for (String searchDirectoryName : allDirectoryNames) { 1277 if (searchDirectoryName.equals("/")) { 1278 result += searchDirectoryName; 1279 continue; 1280 } 1281 String end = ""; 1282 if (searchDirectoryName.endsWith("/")) { 1283 end = "/"; 1284 } 1285 1286 String[] list = new File(result).list(); 1287 boolean found = false; 1288 String foundDirectoryName = null; 1289 if (list == null) { 1290 if (throwOnFail) { 1291 throw new RuntimeException("!found " + searchDirectoryName + " " + fileName); 1292 } 1293 return null; 1294 } 1295 for (String existingDirectoryName : list) { 1296 if (searchDirectoryName.equalsIgnoreCase(existingDirectoryName + end)) { 1297 if (found) { 1298 if (throwOnFail) { 1299 throw new RuntimeException("found " + existingDirectoryName + " " + foundDirectoryName + " " + fileName); 1300 } 1301 return null; 1302 } 1303 foundDirectoryName = existingDirectoryName; 1304 found = true; 1305 } 1306 } 1307 if (!found) { 1308 if (throwOnFail) { 1309 throw new RuntimeException("!found " + searchDirectoryName + " " + fileName); 1310 } 1311 return null; 1312 } 1313 result += foundDirectoryName + end; 1314 } 1315 1316 return result; 1317 } 1318 1319 public static boolean renameWithCaseChangeFullPath(String fromFileName, String toFileName, boolean throwOnFail) { 1320 List<String> fromAllDirectoryNames = calculateAllDirectoryNames(fromFileName); 1321 List<String> toAllDirectoryNames = calculateAllDirectoryNames(toFileName); 1322 int min = Math.min(fromAllDirectoryNames.size(), toAllDirectoryNames.size()); 1323 String fromPath = ""; 1324 String toPath = ""; 1325 for (int i = 0; i < min; i++) { 1326 String fromDirectoryName = fromAllDirectoryNames.get(i); 1327 String toDirectoryName = toAllDirectoryNames.get(i); 1328 fromPath += fromDirectoryName; 1329 toPath += toDirectoryName; 1330 if (fromDirectoryName.equals(toDirectoryName)) { 1331 continue; 1332 } 1333 if (!fromDirectoryName.equalsIgnoreCase(toDirectoryName)) { 1334 break; 1335 } 1336 if (!renameWithCaseChange(fromPath, toPath, throwOnFail)) { 1337 return false; 1338 } 1339 } 1340 1341 if (exists(toFileName) && isDirectory(toFileName)) { 1342 return true; 1343 } 1344 1345 return renameWithCaseChange(fromFileName, toFileName, throwOnFail); 1346 } 1347 1348 public static boolean renameWithCaseChange(String fromFileName, String toFileName, boolean throwOnFail) { 1349 if (fromFileName.equals(toFileName)) { 1350 return true; 1351 } 1352 1353 File fromFile = new File(fromFileName); 1354 String fromFileNameLowerCase = fromFileName.toLowerCase(); 1355 String toFileNameLowerCase = toFileName.trim().toLowerCase(); 1356 if (fromFileNameLowerCase.equals(toFileNameLowerCase)) { 1357 String path = calculatePath(fromFileName); 1358 if (fromFile.isDirectory()) { 1359 path = path.substring(0, path.length() - 1); 1360 } 1361 int number = 1; 1362 do { 1363 String tempFileName = path + number++ + ".temp"; 1364 File tempFile = new File(tempFileName); 1365 if (!tempFile.exists()) { 1366 if (!fromFile.renameTo(tempFile)) { 1367 if (throwOnFail) { 1368 throw new RuntimeException("!fromFile.renameTo(tempFile) \"" + fromFile + "\" \"" + tempFile + "\""); 1369 } 1370 return false; 1371 } 1372 fromFile = tempFile; 1373 break; 1374 } 1375 } while (true); 1376 } 1377 1378 String path = calculatePath(toFileName); 1379 if (fromFile.isDirectory()) { 1380 path = calculateParentPathFromPath(path); 1381 } 1382 mkdirs(path); 1383 1384 File toFile = new File(toFileName); 1385 if (!fromFile.renameTo(toFile)) { 1386 if (throwOnFail) { 1387 throw new RuntimeException("!fromFile.renameTo(toFile) " + fromFile + " " + toFile); 1388 } 1389 return false; 1390 } 1391 return true; 1392 } 1393 1394 public static void rename(String fromFileName, String toFileName) { 1395 rename(fromFileName, toFileName, true); 1396 } 1397 1398 public static boolean rename(String fromFileName, String toFileName, boolean throwOnFail) { 1399 return rename(new File(fromFileName), new File(toFileName), throwOnFail); 1400 } 1401 1402 public static boolean rename(File fromFileName, File toFileName, boolean throwOnFail) { 1403 validateFileName(toFileName.toString()); 1404 if (toFileName.exists()) { 1405 if (throwOnFail) { 1406 throw new RuntimeException("toFileName.exists() \"" + toFileName + "\""); 1407 } 1408 return false; 1409 } 1410 boolean renamed = fromFileName.renameTo(toFileName); 1411 if (renamed) { 1412 if (fromFileName.exists()) { 1413 if (throwOnFail) { 1414 throw new RuntimeException("fromFileName.exists after rename\"" + fromFileName + "\""); 1415 } 1416 return false; 1417 } 1418 } else { 1419 if (Util.isWindowsOS()) { 1420 renamed = renameWithCaseChange(fromFileName.toString(), toFileName.toString(), throwOnFail); 1421 if (renamed) { 1422 return renamed; 1423 } 1424 } 1425 1426 if (fromFileName.isDirectory()) { 1427 throw new RuntimeException("Rename / move of directories across mount point / drives is not supported.\n" 1428 + "From file name: \"" + fromFileName.toString() + "\"\n" 1429 + "To file name: \"" + toFileName.toString() + "\"\n" 1430 + "(Or some other rename error occurred)"); 1431 } 1432 1433 boolean ok = copy(fromFileName.toString(), toFileName.toString(), false, true, throwOnFail); 1434 if (!ok) { 1435 return false; 1436 } 1437 if (!delete(fromFileName.toString(), throwOnFail)) { 1438 if (throwOnFail) { 1439 throw new RuntimeException("The file \"" + fromFileName + "\" could not be deleted"); 1440 } 1441 return false; 1442 } 1443 } 1444 return true; 1445 } 1446 1447 public static void copy(String fromFileName, String toFileName) { 1448 copy(fromFileName, toFileName, false); 1449 } 1450 1451 public static void copy(String fromFileName, String toFileName, boolean overwriteOnExists) { 1452 copy(fromFileName, toFileName, overwriteOnExists, true, true); 1453 } 1454 1455 public static boolean copy(String fromFileName, String toFileName, boolean overwriteOnExists, boolean copyLastModified, boolean throwOnFail) { 1456 if (fromFileName.equals(toFileName)) { 1457 if (throwOnFail) { 1458 throw new RuntimeException("ERROR: File names are equals \"" + fromFileName + "\" \"" + toFileName + "\""); 1459 } 1460 return false; 1461 } 1462 1463 File fromFile = new File(fromFileName); 1464 String fromFileNameLowerCase = fromFileName.toLowerCase(); 1465 String toFileNameLowerCase = toFileName.trim().toLowerCase(); 1466 if (fromFileNameLowerCase.equals(toFileNameLowerCase) && Util.isWindowsOS()) { 1467 if (throwOnFail) { 1468 throw new RuntimeException("ERROR: File names in lower case are equal \"" + fromFileName + "\" \"" + toFileName + "\""); 1469 } 1470 return false; 1471 } 1472 1473 if (!fromFile.exists()) { 1474 throw new RuntimeException("Internal error: From file \"" + fromFile + "\" doesn't exist!"); 1475 } 1476 if (fromFile.isDirectory()) { 1477 throw new RuntimeException("From file \"" + fromFile + "\" is a directory, and copying directories is not supported"); 1478 } 1479 1480 BufferedInputStream in; 1481 try { 1482 in = new BufferedInputStream(new FileInputStream(fromFileName)); 1483 } catch (Exception e) { 1484 throw new RuntimeException(e); 1485 } 1486 1487 long inLength = fromFile.length(); 1488 boolean result = copy(in, inLength, toFileName, overwriteOnExists, throwOnFail); 1489 if (!result) { 1490 return result; 1491 } 1492 1493 if (copyLastModified) { 1494 long lastModified = fromFile.lastModified(); 1495 setLastModified(toFileName, lastModified); 1496 } 1497 1498 if (Util.isLinuxOS()) { 1499 boolean canRead = fromFile.canRead(); 1500 boolean canWrite = fromFile.canWrite(); 1501 boolean canExecute = fromFile.canExecute(); 1502 if (canRead) { 1503 if (!setReadable(toFileName, true, throwOnFail)) { 1504 return false; 1505 } 1506 } 1507 if (canWrite) { 1508 if (!setWritable(toFileName, true, throwOnFail)) { 1509 return false; 1510 } 1511 } 1512 if (canExecute) { 1513 if (!setExecutable(toFileName, true, throwOnFail)) { 1514 return false; 1515 } 1516 } 1517 } 1518 1519 // TODO Remove this extra verification 1520 if (!compareFiles(fromFileName, toFileName)) { 1521 throw new RuntimeException("Internal error: The files are not equals!!!"); 1522 } 1523 1524 return result; 1525 } 1526 1527 public static final long COPY_IN_LENGTH_UNKNOWN = -1; 1528 1529 public static boolean copy(BufferedInputStream in, long inLength, String toFileName, boolean overwriteOnExists, boolean throwOnFail) { 1530 validateFileName(toFileName); 1531 File toDirectory = new File(calculatePath(toFileName)); 1532 if (toDirectory.toString().length() != 0) { 1533 mkdirs(toDirectory, throwOnFail); 1534 } 1535 if (exists(toFileName)) { 1536 if (!overwriteOnExists) { 1537 if (throwOnFail) { 1538 throw new RuntimeException("ERROR: To file already exists \"" + toFileName + "\""); 1539 } 1540 return false; 1541 } 1542 } 1543 1544 try { 1545 ProgressState progressState = ProgressThreadData.createProgressState(); 1546 if (progressState != null) { 1547 progressState.setName("Copying file " + toFileName); 1548 if (inLength != COPY_IN_LENGTH_UNKNOWN) { 1549 progressState.setMaximum((int)(inLength)); 1550 } 1551 progressState.setUseUnits(true); 1552 } 1553 1554 byte[] buffer = new byte[1000000]; 1555 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(toFileName)); 1556 while (true) { 1557 int count = in.read(buffer); 1558 if (count == -1) { 1559 break; 1560 } 1561 out.write(buffer, 0, count); 1562 if (progressState != null) { 1563 progressState.setCurrent(progressState.getCurrent() + count); 1564 } 1565 } 1566 out.close(); 1567 in.close(); 1568 1569 ProgressThreadData.disposeProgressState(progressState); 1570 1571 if (!exists(toFileName)) { 1572 throw new RuntimeException("Internal error: To file doesn't exist!"); 1573 } 1574 File toFile = new File(toFileName); 1575 if (inLength != COPY_IN_LENGTH_UNKNOWN && inLength != toFile.length()) { 1576 throw new RuntimeException("Internal error: From and to file length are different: " + inLength + " " + toFile.length()); 1577 } 1578 } catch (Exception e) { 1579 if (in != null) { 1580 try { 1581 in.close(); 1582 } catch (IOException e1) { 1583 throw new RuntimeException(e1); 1584 } 1585 } 1586 if (throwOnFail) { 1587 throw new RuntimeException(e); 1588 } 1589 1590 System.out.println(e.getMessage()); 1591 System.out.println("To file name: " + toFileName); 1592 e.printStackTrace(); 1593 1594 return false; 1595 } 1596 1597 return true; 1598 } 1599 1600 public static void copyDirectoryTree(String fromPath, String toPath, boolean echo) { 1601 copyDirectoryTree(fromPath, toPath, echo, false); 1602 } 1603 1604 public static void copyDirectoryTree(String fromPath, String toPath, boolean echo, boolean overwriteOnExists) { 1605 copyDirectoryTree(fromPath, toPath, echo, overwriteOnExists, true, true); 1606 } 1607 1608 public static boolean copyDirectoryTree(String fromPath, String toPath, boolean echo, boolean overwriteOnExists, boolean copyLastModified, boolean throwOnFail) { 1609 Collection<String> files = findAllFilesInDirectory(fromPath, true); 1610 for (Iterator<String> iterator = files.iterator(); iterator.hasNext();) { 1611 String fileName = iterator.next(); 1612 if (!fileName.startsWith(fromPath)) { 1613 throw new RuntimeException("Internal error"); 1614 } 1615 String offsetFileName = fileName.substring(fromPath.length()); 1616 String newFileName = toPath + offsetFileName; 1617 boolean result = copy(fileName, newFileName, overwriteOnExists, copyLastModified, throwOnFail); 1618 if (!result) { 1619 return false; 1620 } 1621 if (echo) { 1622 System.out.println("File copied from \"" + fileName + "\" to \"" + newFileName + "\""); 1623 } 1624 } 1625 return true; 1626 } 1627 1628 public static void delete(String fileName) { 1629 delete(fileName, true); 1630 } 1631 1632 public static boolean delete(String fileName, boolean throwOnFail) { 1633 if (!exists(fileName)) { 1634 if (throwOnFail) { 1635 throw new RuntimeException("File \"" + fileName + "\" doesn't exist"); 1636 } 1637 return false; 1638 } 1639 if (!new File(fileName).delete()) { 1640 if (throwOnFail) { 1641 throw new RuntimeException("Delete of \"" + fileName + "\" failed"); 1642 } 1643 return false; 1644 } 1645 return true; 1646 } 1647 1648 public static class DeleteDirectoryData { 1649 public List<String> filesDeleted; 1650 public List<String> directoriesDeleted; 1651 public boolean failed; 1652 1653 @Override 1654 public String toString() { 1655 String result = ""; 1656 if (filesDeleted != null && filesDeleted.size() > 0) { 1657 result = "Files: " + filesDeleted; 1658 } 1659 if (directoriesDeleted != null && directoriesDeleted.size() > 0) { 1660 if (result.length() > 0) { 1661 result += "\n"; 1662 } 1663 result += "Directories: " + directoriesDeleted + "\n"; 1664 } 1665 if (failed) { 1666 if (result.length() > 0) { 1667 result += "\n"; 1668 } 1669 result += "Failed"; 1670 } 1671 return result; 1672 } 1673 } 1674 1675 public static DeleteDirectoryData deleteDirectoryTree(String path, boolean echo) { 1676 return deleteDirectoryTree(path, echo, true); 1677 } 1678 1679 public static DeleteDirectoryData deleteDirectoryTree(String path, boolean echo, boolean throwOnFail) { 1680 DeleteDirectoryData deleteDirectoryData = new DeleteDirectoryData(); 1681 Collection<String> files = findAllFilesInDirectory(path, true); 1682 for (String fileName : files) { 1683 boolean deleted = delete(fileName, throwOnFail); 1684 if (!deleted) { 1685 deleteDirectoryData.failed = true; 1686 1687 if (echo) { 1688 System.out.println("Deletion of the file \"" + fileName + "\" failed"); 1689 } 1690 1691 return deleteDirectoryData; 1692 } 1693 1694 if (deleteDirectoryData.filesDeleted == null) { 1695 deleteDirectoryData.filesDeleted = new ArrayList<String>(); 1696 } 1697 deleteDirectoryData.filesDeleted.add(fileName); 1698 1699 if (echo) { 1700 System.out.println("The file \"" + fileName + "\" was deleted"); 1701 } 1702 } 1703 1704 List<String> allDirectoriesInDirectory = findAllDirectoriesInDirectoryAsList(path, true); 1705 // Hack to make sure that subdirectories are deleted before parent directory. 1706 Collections.sort(allDirectoriesInDirectory, new Comparator<String>() { 1707 public int compare(String s1, String s2) { 1708 return s2.length() - s1.length(); 1709 } 1710 }); 1711 1712 for (String childPath : allDirectoriesInDirectory) { 1713 if (!deleteDirectory(deleteDirectoryData, childPath, echo, throwOnFail)) { 1714 return deleteDirectoryData; 1715 } 1716 } 1717 1718 deleteDirectory(deleteDirectoryData, path, echo, throwOnFail); 1719 1720 return deleteDirectoryData; 1721 } 1722 1723 private static boolean deleteDirectory(DeleteDirectoryData deleteDirectoryData, String path, boolean echo, boolean throwOnFail) { 1724 boolean deleted = delete(path, throwOnFail); 1725 if (!deleted) { 1726 deleteDirectoryData.failed = true; 1727 1728 if (echo) { 1729 System.out.println("Deletion of the directory \"" + path + "\" failed"); 1730 } 1731 1732 return false; 1733 } 1734 1735 if (deleteDirectoryData.directoriesDeleted == null) { 1736 deleteDirectoryData.directoriesDeleted = new ArrayList<String>(); 1737 } 1738 deleteDirectoryData.directoriesDeleted.add(path); 1739 1740 if (echo) { 1741 System.out.println("The directory \"" + path + "\" was deleted"); 1742 } 1743 1744 return true; 1745 } 1746 1747 public static class DirectoryTree { 1748 public String name; 1749 public String fullName; 1750 public List<DirectoryTree> subdirectories; 1751 public String toString() { 1752 return fullName; 1753 } 1754 } 1755 1756 public static List<String> findAllDirectoriesInDirectoryAsList(String path, boolean includeSubdirectories) { 1757 return findAllDirectoriesInDirectoryAsList(path, includeSubdirectories, null); 1758 } 1759 1760 public static List<String> findAllDirectoriesInDirectoryAsList(String path, boolean includeSubdirectories, List<String> excludeDirectories) { 1761 return findAllDirectoriesInDirectoryAsList(path, includeSubdirectories, excludeDirectories, null); 1762 } 1763 1764 public static List<String> findAllDirectoriesInDirectoryAsList(String path, boolean includeSubdirectories, List<String> excludeDirectories, String progressStateLabel) { 1765 DirectoryTree directoryTree = findAllDirectoriesInDirectory(path, includeSubdirectories, true, excludeDirectories, progressStateLabel); 1766 ArrayList<String> result = new ArrayList<String>(); 1767 addDirectoryTree(result, directoryTree); 1768 return result; 1769 } 1770 1771 private static void addDirectoryTree(ArrayList<String> paths, DirectoryTree parentDirectoryTree) { 1772 if (parentDirectoryTree == null) { 1773 return ; 1774 } 1775 1776 if (parentDirectoryTree.subdirectories == null) { 1777 return ; 1778 } 1779 1780 Iterator<DirectoryTree> i = parentDirectoryTree.subdirectories.iterator(); 1781 while (i.hasNext()) { 1782 DirectoryTree directoryTree = i.next(); 1783 paths.add(directoryTree.fullName); 1784 addDirectoryTree(paths, directoryTree); 1785 } 1786 } 1787 1788 public static DirectoryTree findAllDirectoriesInDirectory(String path, boolean includeSubdirectories) { 1789 return findAllDirectoriesInDirectory(path, includeSubdirectories, true, null); 1790 } 1791 1792 public static DirectoryTree findAllDirectoriesInDirectory(String path, boolean includeSubdirectories, List<String> excludeDirectories) { 1793 return findAllDirectoriesInDirectory(path, includeSubdirectories, true, excludeDirectories); 1794 } 1795 1796 public static DirectoryTree findAllDirectoriesInDirectory(String path, boolean includeSubdirectories, boolean caseSensitive, List<String> excludeDirectories) { 1797 return findAllDirectoriesInDirectory(path, includeSubdirectories, caseSensitive, excludeDirectories, null); 1798 } 1799 1800 public static DirectoryTree findAllDirectoriesInDirectory(String path, boolean includeSubdirectories, boolean caseSensitive, List<String> excludeDirectories, String progressStateLabel) { 1801 ProgressState progressState = ProgressThreadData.createProgressState(); 1802 if (progressState != null) { 1803 if (progressStateLabel == null) { 1804 progressState.setName("Finding directories in directory " + path); 1805 } else { 1806 progressState.setName(progressStateLabel); 1807 } 1808 } 1809 FilterData filterData = calculateFilter(path, caseSensitive); 1810 path = filterData.path; 1811 File file = new File(path); 1812 DirectoryTree result = null; 1813 if (file.exists()) { 1814 result = findAllDirectoriesInDirectory(path, filterData.filter, includeSubdirectories, caseSensitive, excludeDirectories, progressState); 1815 } 1816 ProgressThreadData.disposeProgressState(progressState); 1817 return result; 1818 } 1819 1820 private static DirectoryTree findAllDirectoriesInDirectory(String path, String filter, boolean includeSubdirectories, boolean caseSensitive, List<String> excludeDirectories, ProgressState progressState) { 1821 File file = new File(path); 1822 File[] filesArray = file.listFiles((FileFilter)null); 1823 DirectoryTree result = new DirectoryTree(); 1824 result.name = calculateLastDirectoryName(path); 1825 result.fullName = path; 1826 if (filesArray == null) { 1827 return result; 1828 } 1829 1830 if (progressState != null) { 1831 progressState.setMaximum(filesArray.length); 1832 } 1833 1834 for (int i = 0; i < filesArray.length; i++) { 1835 if (progressState != null) { 1836 progressState.incCurrent(); 1837 } 1838 1839 if (!filesArray[i].isDirectory()) { 1840 continue; 1841 } 1842 1843 if (!StringUtil.doesStringMatchWildcard(filesArray[i].getName(), filter, false)) { 1844 continue; 1845 } 1846 1847 if (result.subdirectories == null) { 1848 result.subdirectories = new ArrayList<DirectoryTree>(); 1849 } 1850 1851 String subdirectory = filesArray[i].getAbsolutePath() + File.separator; 1852 if (excludeDirectory(excludeDirectories, subdirectory, caseSensitive)) { 1853 continue; 1854 } 1855 1856 DirectoryTree temp; 1857 if (includeSubdirectories) { 1858 ProgressState subProgressState = null; 1859 if (progressState != null) { 1860 subProgressState = ProgressThreadData.createProgressState(); 1861 String name = calculateLastDirectoryNameNoIO(subdirectory); 1862 subProgressState.setName(name); 1863 } 1864 temp = findAllDirectoriesInDirectory(subdirectory, filter, includeSubdirectories, caseSensitive, excludeDirectories, subProgressState); 1865 ProgressThreadData.disposeProgressState(subProgressState); 1866 } else { 1867 temp = new DirectoryTree(); 1868 temp.name = calculateLastDirectoryName(subdirectory); 1869 temp.fullName = subdirectory; 1870 } 1871 result.subdirectories.add(temp); 1872 } 1873 1874 if (result.subdirectories != null) { 1875 Collections.sort(result.subdirectories, new Comparator<DirectoryTree>() { 1876 @Override 1877 public int compare(DirectoryTree directoryTree1, DirectoryTree directoryTree2) { 1878 return directoryTree1.fullName.compareTo(directoryTree2.fullName); 1879 } 1880 }); 1881 } 1882 1883 return result; 1884 } 1885 1886 public static List<String> findAllFilesInDirectory(String path, boolean includeSubdirectories) { 1887 return findAllFilesInDirectory(path, includeSubdirectories, false); 1888 } 1889 1890 public static List<String> findAllFilesInDirectory(String path, boolean includeSubdirectories, boolean caseSensitive) { 1891 return findAllFilesInDirectory(path, includeSubdirectories, caseSensitive, null); 1892 } 1893 1894 public static List<String> findAllFilesInDirectory(String path, boolean includeSubdirectories, List<String> excludeDirectories) { 1895 return findAllFilesInDirectory(path, includeSubdirectories, false, excludeDirectories); 1896 } 1897 1898 public static List<String> findAllFilesInDirectory(String path, boolean includeSubdirectories, boolean caseSensitive, List<String> excludeDirectories) { 1899 return findAllFilesInDirectory(path, includeSubdirectories, caseSensitive, excludeDirectories, null); 1900 } 1901 1902 public static List<String> findAllFilesInDirectory(String path, boolean includeSubdirectories, boolean caseSensitive, List<String> excludeDirectories, String progressStateLabel) { 1903 if (path == null) { 1904 throw new NullPointerException("path == null"); 1905 } 1906 1907 ArrayList<String> result = new ArrayList<String>(); 1908 ProgressState progressState = ProgressThreadData.createProgressState(); 1909 if (progressState != null) { 1910 if (progressStateLabel == null) { 1911 progressState.setName("Finding files in path " + path); 1912 } else { 1913 progressState.setName(progressStateLabel); 1914 } 1915 } 1916 1917 findAllFilesInDirectory(result, path, includeSubdirectories, caseSensitive, excludeDirectories, progressState); 1918 1919 ProgressThreadData.disposeProgressState(progressState); 1920 1921 Util.sortStringListCaseInsensitiveOrder(result); 1922 1923 return result; 1924 } 1925 1926 private static void findAllFilesInDirectory(Collection<String> files, String path, boolean includeSubdirectories, boolean caseSensitive, List<String> excludeDirectories, ProgressState progressState) { 1927 FilterData filterData = calculateFilter(path, caseSensitive); 1928 1929 List<String> absoluteExcludePaths = null; 1930 if (excludeDirectories != null) { 1931 absoluteExcludePaths = new ArrayList<String>(); 1932 for (String excludePath : excludeDirectories) { 1933 if (!isAbsolute(excludePath)) { 1934 excludePath = calculateAbsolutePath(filterData.path, excludePath); 1935 } 1936 1937 absoluteExcludePaths.add(excludePath); 1938 } 1939 } 1940 1941 findAllFilesInDirectoryLocal(files, filterData.path, filterData.filter, includeSubdirectories, caseSensitive, absoluteExcludePaths, progressState); 1942 } 1943 1944 public static class FilterData { 1945 public String path; 1946 public String filter; 1947 1948 @Override 1949 public String toString() { 1950 return path + (path.endsWith(File.separator) ? "" : File.separator) + filter; 1951 } 1952 } 1953 1954 public static FilterData calculateFilter(String path, boolean caseSensitive) { 1955 if (path == "" || path == ".") { 1956 path = "." + File.separator; 1957 } 1958 File file = new File(path); 1959 String filter = ""; 1960 if (!path.endsWith(File.separator) && (!file.exists() || !file.isDirectory())) { 1961 filter = file.getName(); 1962 if (file.isFile() || filter != "") { 1963 file = file.getParentFile(); 1964 if (file != null) { 1965 path = file.getPath() + File.separator; 1966 } else { 1967 path = "."; 1968 } 1969 } 1970 } 1971 if (filter == "") { 1972 filter = "*"; 1973 } 1974 if (!caseSensitive) { 1975 filter = filter.toLowerCase(); 1976 } 1977 1978 FilterData filterData = new FilterData(); 1979 filterData.path = path; 1980 filterData.filter = filter; 1981 return filterData; 1982 } 1983 1984 private static boolean excludeDirectory(List<String> excludeDirectories, String subdirectory, boolean caseSensitive) { 1985 if (excludeDirectories == null || excludeDirectories.size() == 0) { 1986 return false; 1987 } 1988 1989 if (!caseSensitive) { 1990 subdirectory = subdirectory.toLowerCase(); 1991 } 1992 1993 Iterator<String> i2 = excludeDirectories.iterator(); 1994 while (i2.hasNext()) { 1995 String excludeDirectory = i2.next(); 1996 if (!caseSensitive) { 1997 excludeDirectory = excludeDirectory.toLowerCase(); 1998 } 1999 if (subdirectory.startsWith(excludeDirectory)) { 2000 return true; 2001 } 2002 } 2003 2004 return false; 2005 } 2006 2007 private static void findAllFilesInDirectoryLocal(Collection<String> files, String path, String filter, boolean includeSubdirectories, boolean caseSensitive, List<String> excludeDirectories, ProgressState progressState) { 2008 File file = new File(path); 2009 File[] filesArray = file.listFiles((FileFilter)null); 2010 if (filesArray == null) { 2011 return ; 2012 } 2013 2014 if (progressState != null) { 2015 progressState.setMaximum(filesArray.length); 2016 } 2017 2018 for (int i = 0; i < filesArray.length; i++) { 2019 if (progressState != null) { 2020 progressState.incCurrent(); 2021 } 2022 2023 if (filesArray[i].isFile()) { 2024 String fileName = filesArray[i].getName(); 2025 if (!caseSensitive) { 2026 fileName = fileName.toLowerCase(); 2027 } 2028 if (StringUtil.doesStringMatchWildcard(fileName, filter, false)) { 2029 try { 2030 String canonicalPath = filesArray[i].getCanonicalPath(); 2031 files.add(canonicalPath); 2032 } catch (IOException e) { 2033 throw new RuntimeException(e); 2034 } 2035 } 2036 } 2037 2038 String subdirectory = filesArray[i].getAbsolutePath() + File.separator; 2039 if (excludeDirectory(excludeDirectories, subdirectory, caseSensitive)) { 2040 continue; 2041 } 2042 2043 if (includeSubdirectories && filesArray[i].isDirectory()) { 2044/* if (Util.isLinuxOS() && isSymbolicLink(subdirectory)) { // TODO Remove 2045 System.out.println("Directory \"" + subdirectory + "\" is a link => no follow"); 2046 continue; 2047 }*/ 2048 2049 ProgressState subProgressState = null; 2050 if (progressState != null) { 2051 subProgressState = ProgressThreadData.createProgressState(); 2052 String name = calculateLastDirectoryNameNoIO(subdirectory); 2053 subProgressState.setName(name); 2054 } 2055 findAllFilesInDirectoryLocal(files, subdirectory, filter, includeSubdirectories, caseSensitive, excludeDirectories, subProgressState); 2056 ProgressThreadData.disposeProgressState(subProgressState); 2057 } 2058 } 2059 } 2060 2061 public static boolean isSymbolicLink(String fileName) { 2062 Path link = Paths.get(fileName); 2063 return Files.isSymbolicLink(link); 2064 } 2065 2066 public static boolean doesDirectoryContainAFile(String path) { 2067 File file = new File(path); 2068 File[] filesArray = file.listFiles((FileFilter)null); 2069 if (filesArray == null) { 2070 return false; 2071 } 2072 2073 for (int i = 0; i < filesArray.length; i++) { 2074 if (filesArray[i].isFile()) { 2075 return true; 2076 } 2077 2078 if (filesArray[i].isDirectory()) { 2079 String subdirectory = filesArray[i].getAbsolutePath() + File.separator; 2080 if (doesDirectoryContainAFile(subdirectory)) { 2081 return true; 2082 } 2083 } 2084 } 2085 2086 return false; 2087 } 2088 2089 public static boolean compareFiles(String fileName1, String fileName2) { 2090 return compareFilesEqualsBytes(fileName1, fileName2) >= 0; 2091 } 2092 2093 public static final long COMPARE_ERROR = -1; 2094 2095 /** 2096 * Compares the two files. 2097 * @return If the files are identical, then the number of bytes compared is returned. If the files are not identical, then the first different byte position is returned negative. On error -1 is returned. 2098 */ 2099 public static long compareFilesEqualsBytes(String fileName1, String fileName2) { 2100 try { 2101 BufferedInputStream in1; 2102 try { 2103 in1 = new BufferedInputStream(new FileInputStream(fileName1)); 2104 } catch (FileNotFoundException e) { 2105 return COMPARE_ERROR; 2106 } 2107 2108 BufferedInputStream in2; 2109 try { 2110 in2 = new BufferedInputStream(new FileInputStream(fileName2)); 2111 } catch (FileNotFoundException e) { 2112 in1.close(); 2113 return COMPARE_ERROR; 2114 } 2115 2116 long result = 0; 2117 boolean equals = true; 2118 byte[] buffer1 = new byte[10000]; 2119 byte[] buffer2 = new byte[10000]; 2120 ProgressState progressState = ProgressThreadData.createProgressState(); 2121 if (progressState != null) { 2122 progressState.setName("Comparing files " + fileName1 + " and " + fileName2); 2123 long size = size(fileName1); 2124 progressState.setMaximum((int)(size)); 2125 progressState.setUseUnits(true); 2126 } 2127 do { 2128 int byteRead1 = in1.read(buffer1); 2129 if (byteRead1 == -1) { 2130 break; 2131 } 2132 int byteRead2 = in2.read(buffer2); 2133 if (byteRead2 == -1) { 2134 break; 2135 } 2136 if (byteRead1 != byteRead2) { 2137 result += Math.min(byteRead1, byteRead2); 2138 result = -result; 2139 break; 2140 } 2141 for (int i = 0; i < byteRead1; i++) { 2142 if (buffer1[i] != buffer2[i]) { 2143 result += i + 1; 2144 result = -result; 2145 equals = false; 2146 break; 2147 } 2148 } 2149 if (equals) { 2150 result += byteRead1; 2151 if (progressState != null) { 2152 progressState.setCurrent(progressState.getCurrent() + byteRead1); 2153 } 2154 } 2155 } while (equals); 2156 2157 in1.close(); 2158 in2.close(); 2159 2160 ProgressThreadData.disposeProgressState(progressState); 2161 2162 return result; 2163 } catch (IOException e) { 2164 return COMPARE_ERROR; 2165 } 2166 } 2167 2168 public static boolean getReadable(String fileName) { 2169 return new File(fileName).canRead(); 2170 } 2171 2172 public static void setReadable(String fileName, boolean readable) { 2173 setReadable(fileName, true); 2174 } 2175 2176 public static boolean setReadable(String fileName, boolean readable, boolean throwOnFail) { 2177 if (Util.getOSType() != OsType.LINUX && Util.getOSType() != OsType.MAC) { 2178 return true; 2179 } 2180 2181 boolean succeeded = new File(fileName).setReadable(readable, false); 2182 if (!succeeded && throwOnFail) { 2183 throw new RuntimeException("setReadable failed for file \"" + fileName + "\""); 2184 } 2185 2186 return succeeded; 2187 } 2188 2189 public static String findExistingParent(String fileName) { 2190 fileName = calculateAbsoluteFileName(fileName); 2191 if (exists(fileName) && !isDirectory(fileName)) { 2192 return calculatePath(fileName); 2193 } 2194 2195 boolean first = true; 2196 while (!exists(fileName) && fileName.length() > 0) { 2197 if (first) { 2198 first = false; 2199 fileName = calculatePath(fileName); 2200 continue; 2201 } 2202 fileName = calculateParentPathFromPath(fileName); 2203 } 2204 if (!fileName.endsWith(File.separator)) { 2205 fileName += File.separator; 2206 } 2207 2208 return fileName; 2209 } 2210 2211 public static boolean getWritable(String fileName) { 2212 if (Util.isWindowsOS()) { 2213 // canWrite() will only return the read-only attribute on Windows, not whether the file actually can be written. The checkWriteAccess() method will to this, but it is slower. 2214 return checkWriteAccess(fileName); 2215 } 2216 2217 String existingParent = findExistingParent(fileName); 2218 return new File(existingParent).canWrite(); 2219 } 2220 2221 public static void setWritable(String fileName, boolean writable) { 2222 setWritable(fileName, true); 2223 } 2224 2225 public static boolean setWritable(String fileName, boolean writable, boolean throwOnFail) { 2226 if (Util.getOSType() != OsType.LINUX && Util.getOSType() != OsType.MAC) { 2227 return true; 2228 } 2229 2230 boolean succeeded = new File(fileName).setWritable(writable, false); 2231 if (!succeeded && throwOnFail) { 2232 throw new RuntimeException("setWritable failed for file \"" + fileName + "\""); 2233 } 2234 2235 return succeeded; 2236 } 2237 2238 public static boolean getExecutable(String fileName) { 2239 return new File(fileName).canExecute(); 2240 } 2241 2242 public static void setExecutable(String fileName, boolean executable) { 2243 setExecutable(fileName, executable, true); 2244 } 2245 2246 public static boolean setExecutable(String fileName, boolean executable, boolean throwOnFail) { 2247 if (Util.getOSType() != OsType.LINUX && Util.getOSType() != OsType.MAC) { 2248 return true; 2249 } 2250 2251 boolean succeeded = new File(fileName).setExecutable(executable, false); 2252 if (!succeeded && throwOnFail) { 2253 throw new RuntimeException("setExecutable failed for file \"" + fileName + "\""); 2254 } 2255 2256 return succeeded; 2257 } 2258 2259 public static long getFreeSpace(String path) { 2260 File file = new File(path); 2261 long freeSpace = file.getFreeSpace(); 2262 if (Util.isWindowsOS()) { 2263 if (freeSpace == 0 && !file.exists()) { 2264 file = new File("." + File.separator + path); 2265 freeSpace = file.getFreeSpace(); 2266 } 2267 2268 while (freeSpace == 0 && !file.exists()) { 2269 file = file.getParentFile(); 2270 if (file == null) { 2271 break; 2272 } 2273 freeSpace = file.getFreeSpace(); 2274 } 2275 } 2276 2277 if (Util.isLinuxOS()) { 2278 while (freeSpace == 0 && file != null && !file.exists()) { 2279 file = file.getParentFile(); 2280 if (file == null) { 2281 break; 2282 } 2283 freeSpace = file.getFreeSpace(); 2284 } 2285 } 2286 2287 return freeSpace; 2288 } 2289 2290 /** 2291 * Check for write access using the creation of an actual file. 2292 * <br> 2293 * See {@link #getWritable(String)} for details 2294 */ 2295 public static boolean checkWriteAccess(String fileName) { 2296 String existingParent = findExistingParent(fileName); 2297 2298 String tempFileName; 2299 try { 2300 tempFileName = createTempFile(existingParent, DEFAULT_TEMP_FILE_PREFIX + "FileUtil - checkWriteAccess - ", ".txt"); 2301 } catch (Exception e) { 2302 return false; 2303 } 2304 2305 if (!exists(tempFileName)) { 2306 throw new RuntimeException("The file doesn't exist, after a creation has been attempted"); 2307 } 2308 2309 delete(tempFileName); 2310 2311 if (exists(tempFileName)) { 2312 throw new RuntimeException("The file exists after it has been attempted to be deleted"); 2313 } 2314 2315 return true; 2316 } 2317 2318 public static class LockFile implements AutoCloseable { 2319 private String lockFileName; 2320 private FileOutputStream fileOutputStream; 2321 private FileChannel channel; 2322 private FileLock lock; 2323 private boolean valid; 2324 2325 public LockFile(String plockFileName, FileOutputStream pfileOutputStream, FileChannel pchannel, FileLock plock) { 2326 lockFileName = plockFileName; 2327 fileOutputStream = pfileOutputStream; 2328 channel = pchannel; 2329 lock = plock; 2330 valid = true; 2331 } 2332 2333 public synchronized void releaseLockAndDeleteLockFile() { 2334 releaseLockAndDeleteLockFile(true, null); 2335 } 2336 2337 private synchronized void releaseLockAndDeleteLockFile(boolean check, String closedBy) { 2338 try { 2339 if (!valid) { 2340 if (check) { 2341 throw new RuntimeException("!valid " + this); 2342 } 2343 2344 return ; 2345 } 2346 valid = false; 2347 2348 if (closedBy != null) { 2349 Util.printMessageWithSourceLine("Closed by: " + closedBy); 2350 } 2351 2352 // Linux only: 2353 // If delete only is done with the lock, it seems to work. Deleting it after the lock has been closed / released breaks stuff. 2354 // NOTE: The file can be deleted without the lock! 2355 if (!Util.isWindowsOS()) { 2356 if (exists(lockFileName)) { 2357 delete(lockFileName); 2358 } else { 2359 if (check) { 2360 throw new RuntimeException("Lock file \"" + lockFileName + "\" doesn't exist as it should"); 2361 } 2362 } 2363 } 2364 2365 lock.close(); 2366 channel.close(); 2367 fileOutputStream.close(); 2368 2369 if (Util.isWindowsOS()) { 2370 // Windows only: 2371 // As the lock file can't be deleted with the lock, it is deleted after the lock has been released. 2372 // This might fail if some else has taken the lock, therefore only a warning is printed. 2373 if (exists(lockFileName)) { 2374 boolean deleted = delete(lockFileName, false); 2375 if (!deleted) { 2376 System.out.println("WARNING: Deletion of lock file failed"); 2377 } 2378 } 2379 } 2380 } catch (IOException e) { 2381 throw new RuntimeException(e); 2382 } 2383 } 2384 2385 public boolean isValid() { 2386 return valid && exists(lockFileName); 2387 } 2388 2389 @Override 2390 public void close() throws Exception { 2391 releaseLockAndDeleteLockFile(false, "close"); 2392 } 2393 2394 @Override 2395 protected void finalize() throws Throwable { 2396 releaseLockAndDeleteLockFile(false, "finalize"); 2397 } 2398 2399 @Override 2400 public String toString() { 2401 return "Write lock on \"" + lockFileName + "\"" + (valid ? "" : " NOT VALID"); 2402 } 2403 } 2404 2405 public static LockFile createLockFile(String lockFileName) { 2406 return createLockFile(lockFileName, true); 2407 } 2408 2409 public static LockFile createLockFile(String lockFileName, boolean throwOnFail) { 2410 try { 2411 FileOutputStream fileOutputStream = new FileOutputStream(lockFileName); 2412 FileChannel channel = fileOutputStream.getChannel(); 2413 FileLock lock = channel.tryLock(); 2414 if (lock == null) { 2415 try { 2416 fileOutputStream.close(); 2417 } catch (IOException e) { 2418 e.printStackTrace(); 2419 } 2420 2421 if (throwOnFail) { 2422 throw new RuntimeException("Write lock on file \"" + lockFileName + "\" couldn't be achieved"); 2423 } 2424 2425 return null; 2426 } 2427 return new LockFile(lockFileName, fileOutputStream, channel, lock); 2428 } catch (OverlappingFileLockException e) { 2429 return null; 2430 } catch (IOException e) { 2431 if (throwOnFail) { 2432 throw new RuntimeException(e); 2433 } 2434 return null; 2435 } 2436 } 2437 2438 /** 2439 * Finds an available (Non existing) file name in path. 2440 * <br> 2441 * Example usage: 2442 * <pre><code> int number = FileUtil.findAvailableFileName(path, fileName, 0); 2443 * String newFileName = FileUtil.calculateNumberedFileName(path, fileName, number);</code></pre> 2444 * @see #createTempFile(String, String, String) 2445 * @see #calculateNumberedFileName(String, String, int) 2446 */ 2447 public static int findAvailableFileName(String path, String fileName, int number) { 2448 do { 2449 number++; 2450 String tempFileName = calculateNumberedFileName(path, fileName, number); 2451 File file = new File(tempFileName); 2452 if (file.exists()) { 2453 continue; 2454 } 2455 return number; 2456 } while (true); 2457 } 2458 2459 public static void checkForTempFiles(final List<String> fileNames) { 2460 Thread thread = new Thread() { 2461 @Override 2462 public void run() { 2463 for (String fileName : fileNames) { 2464 String absoluteFileName = new File(fileName).getAbsoluteFile().toString(); 2465 String path = calculatePath(absoluteFileName); 2466 final String extension = calculateExtension(absoluteFileName); 2467 String[] tempFiles = new File(path).list(new FilenameFilter() { 2468 public boolean accept(File ppath, String name) { 2469 if (StringUtil.doesStringMatchMultiWildcard(name, DEFAULT_TEMP_FILE_PREFIX + "* - *" + extension, false)) { 2470 return true; 2471 } 2472 return false; 2473 } 2474 }); 2475 2476 if (tempFiles != null && tempFiles.length > 0) { 2477 GUIUtil.showWarning("Temp files: " + Arrays.toString(tempFiles)); 2478 Util.openDirectory(path); 2479 } 2480 } 2481 } 2482 }; 2483 thread.setPriority(Thread.MIN_PRIORITY); 2484 thread.start(); 2485 } 2486 2487 /** 2488 * Creates a temporary file in path. 2489 * <br> 2490 * Use the {@link #findAvailableFileName(String, String, int)} to find an available file name. 2491 * @see #findAvailableFileName(String, String, int) 2492 */ 2493 public static String createTempFile(String path, String prefix, String postfix) { 2494 int count = 0; 2495 while (true) { 2496 File file = new File(path + prefix + MathUtil.randomNumber(1000000) + postfix); 2497 try { 2498 if (!file.createNewFile()) { 2499 if (count > 100) { 2500 throw new RuntimeException("count > 100 => createTempFile(Path: \"" + path + "\", prefix: \"" + prefix + "\", \", postfix: \"" + postfix + "\") failed"); 2501 } 2502 2503 count++; 2504 continue; 2505 } 2506 } catch (IOException e) { 2507 throw new RuntimeException("createTempFile(Path: \"" + path + "\", prefix: \"" + prefix + "\", \", postfix: \"" + postfix + "\")", e); 2508 } 2509 2510 return file.toString(); 2511 } 2512 } 2513 2514 public static String getTempPath() { 2515 String tempPath = System.getenv("TEMP"); 2516 if (tempPath != null) { 2517 tempPath += File.separator; 2518 } else { 2519 tempPath = System.getenv("TMPDIR"); 2520 if (tempPath == null) { 2521 tempPath = System.getenv("P_tmpdir"); 2522 if (tempPath == null) { 2523 switch (Util.getOSType()) { 2524 case WINDOWS : 2525 tempPath = WINDOWS_TEMP_PATH; 2526 break; 2527 case LINUX : 2528 tempPath = LINUX_TEMP_PATH; 2529 break; 2530 case MAC : 2531 tempPath = MAC_TEMP_PATH; 2532 break; 2533 default : 2534 throw new RuntimeException("Unknown OS type: " + Util.getOSType()); 2535 } 2536 } 2537 } 2538 } 2539 2540 return tempPath; 2541 } 2542 2543 public static String currentPath() { 2544 return System.getProperty("user.dir") + File.separatorChar; 2545 } 2546 2547 public static String getInstallationPath() { 2548 switch (Util.getOSType()) { 2549 case WINDOWS : 2550 String windows7Path = System.getenv("PROGRAMFILES(X86)"); 2551 if (windows7Path != null) { 2552 return windows7Path + "\\"; 2553 } 2554 2555 String windowsXPPath = System.getenv("PROGRAMFILES"); 2556 if (windowsXPPath != null) { 2557 return windowsXPPath + "\\"; 2558 } 2559 2560 return "C:\\Programs\\"; 2561// break; 2562 case LINUX : 2563 return "/opt/"; 2564// break; 2565 case MAC : 2566 return "/opt/"; 2567// break; 2568 default : 2569 throw new RuntimeException("Unknown OS type: " + Util.getOSType()); 2570 } 2571 } 2572 2573 public static boolean fileContainsText(String fileName, String text) { 2574 return fileContainsText(fileName, text, null); 2575 } 2576 2577 public static boolean fileContainsText(String fileName, String text, String encoding) { 2578 if (!exists(fileName)) { 2579 return false; 2580 } 2581 2582 boolean found = false; 2583 try { 2584 BufferedReader in = createBufferedReader(fileName, encoding); 2585 char[] buffer = new char[100000]; 2586 int offset = 0; 2587 do { 2588 int length = in.read(buffer); 2589 if (length == -1) { 2590 break; 2591 } 2592 for (int i = 0; i < length; i++) { 2593 if (buffer[i] == text.charAt(offset)) { 2594 offset++; 2595 if (offset == text.length()) { 2596 found = true; 2597 break; 2598 } 2599 } else { 2600 i -= offset; 2601 if (i < 0) { 2602 // May cause a bug, but it is too complex to fix. 2603 i = -1; 2604 } 2605 offset = 0; 2606 } 2607 } 2608/* String string = new String(buffer, 0, length); 2609 if (string.contains(text)) { 2610 found = true; 2611 }*/ 2612 } while (!found); 2613 in.close(); 2614 } catch (Exception e) { 2615 throw new RuntimeException(e); 2616 } 2617 2618 return found; 2619 } 2620 2621 /** 2622 * Loads properties from a file and saves them into System properties ({@link java.lang.System#setProperty(String, String)}. 2623 * <br> 2624 * Note: This does NOT overwrite properties that are already set. 2625 */ 2626 public static void loadPropertiesFromFile(String fileName) { 2627 2628 FileInputStream stream = null; 2629 try { 2630 stream = new FileInputStream(fileName); 2631 Properties props = new Properties(); 2632 props.load(stream); 2633 Enumeration<?> properties = props.propertyNames(); 2634 while (properties.hasMoreElements()) { 2635 String property = (String)properties.nextElement(); 2636 if (System.getProperty(property, null) == null) { 2637 String value = (String)props.get(property); 2638 System.setProperty(property, value); 2639 } 2640 } 2641 } catch (FileNotFoundException e) { 2642 throw new RuntimeException(e); 2643 } catch (Exception e) { 2644 throw new RuntimeException(e); 2645 } finally { 2646 if (stream != null) { 2647 try { 2648 stream.close(); 2649 } catch (IOException e) { 2650 throw new RuntimeException(e); 2651 } 2652 } 2653 } 2654 } 2655 2656 public static Properties loadPropertyFile(String fileName) { 2657 return loadPropertyFile(fileName, null); 2658 } 2659 2660 public static Properties loadPropertyFile(String fileName, String encoding) { 2661 BufferedReader bufferedReader = createBufferedReader(fileName, encoding); 2662 Properties properties = new Properties(); 2663 try { 2664 properties.load(bufferedReader); 2665 bufferedReader.close(); 2666 } catch (IOException e) { 2667 throw new RuntimeException(e); 2668 } 2669 return properties; 2670 } 2671}