| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.openapi.util.io; |
| |
| import com.intellij.CommonBundle; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.SystemInfo; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.util.*; |
| import com.intellij.util.concurrency.FixedFuture; |
| import com.intellij.util.containers.ContainerUtil; |
| import com.intellij.util.containers.Convertor; |
| import com.intellij.util.io.URLUtil; |
| import com.intellij.util.text.FilePathHashingStrategy; |
| import com.intellij.util.text.StringFactory; |
| import gnu.trove.TObjectHashingStrategy; |
| import org.intellij.lang.annotations.RegExp; |
| import org.jetbrains.annotations.*; |
| |
| import java.io.*; |
| import java.lang.reflect.Method; |
| import java.util.*; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.FutureTask; |
| import java.util.concurrent.RunnableFuture; |
| import java.util.regex.Pattern; |
| |
| @SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "MethodOverridesStaticMethodOfSuperclass"}) |
| public class FileUtil extends FileUtilRt { |
| |
| @NonNls public static final String ASYNC_DELETE_EXTENSION = ".__del__"; |
| |
| public static final int REGEX_PATTERN_FLAGS = SystemInfo.isFileSystemCaseSensitive ? 0 : Pattern.CASE_INSENSITIVE; |
| |
| public static final TObjectHashingStrategy<String> PATH_HASHING_STRATEGY = FilePathHashingStrategy.create(); |
| |
| public static final TObjectHashingStrategy<File> FILE_HASHING_STRATEGY = |
| SystemInfo.isFileSystemCaseSensitive ? ContainerUtil.<File>canonicalStrategy() : new TObjectHashingStrategy<File>() { |
| @Override |
| public int computeHashCode(File object) { |
| return fileHashCode(object); |
| } |
| |
| @Override |
| public boolean equals(File o1, File o2) { |
| return filesEqual(o1, o2); |
| } |
| }; |
| |
| private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileUtil"); |
| |
| @NotNull |
| public static String join(@NotNull final String... parts) { |
| return StringUtil.join(parts, File.separator); |
| } |
| |
| @Nullable |
| public static String getRelativePath(File base, File file) { |
| return FileUtilRt.getRelativePath(base, file); |
| } |
| |
| @Nullable |
| public static String getRelativePath(@NotNull String basePath, @NotNull String filePath, final char separator) { |
| return FileUtilRt.getRelativePath(basePath, filePath, separator); |
| } |
| |
| @Nullable |
| public static String getRelativePath(@NotNull String basePath, |
| @NotNull String filePath, |
| final char separator, |
| final boolean caseSensitive) { |
| return FileUtilRt.getRelativePath(basePath, filePath, separator, caseSensitive); |
| } |
| |
| public static boolean isAbsolute(@NotNull String path) { |
| return new File(path).isAbsolute(); |
| } |
| |
| /** |
| * Check if the {@code ancestor} is an ancestor of {@code file}. |
| * |
| * @param ancestor supposed ancestor. |
| * @param file supposed descendant. |
| * @param strict if {@code false} then this method returns {@code true} if {@code ancestor} equals to {@code file}. |
| * @return {@code true} if {@code ancestor} is parent of {@code file}; {@code false} otherwise. |
| */ |
| public static boolean isAncestor(@NotNull File ancestor, @NotNull File file, boolean strict) { |
| return isAncestor(ancestor.getPath(), file.getPath(), strict); |
| } |
| |
| public static boolean isAncestor(@NotNull String ancestor, @NotNull String file, boolean strict) { |
| return !ThreeState.NO.equals(isAncestorThreeState(ancestor, file, strict)); |
| } |
| |
| @NotNull |
| public static ThreeState isAncestorThreeState(@NotNull String ancestor, @NotNull String file, boolean strict) { |
| String ancestorPath = toCanonicalPath(ancestor); |
| String filePath = toCanonicalPath(file); |
| |
| if (ancestorPath == null || filePath == null) { |
| return ThreeState.NO; |
| } |
| |
| return startsWith(filePath, ancestorPath, strict, SystemInfo.isFileSystemCaseSensitive, true); |
| } |
| |
| public static boolean startsWith(@NotNull String path, @NotNull String start) { |
| return !ThreeState.NO.equals(startsWith(path, start, false, SystemInfo.isFileSystemCaseSensitive, false)); |
| } |
| |
| public static boolean startsWith(@NotNull String path, @NotNull String start, boolean caseSensitive) { |
| return !ThreeState.NO.equals(startsWith(path, start, false, caseSensitive, false)); |
| } |
| |
| /** |
| * @return ThreeState.YES if same path or immediate parent |
| */ |
| @NotNull |
| private static ThreeState startsWith(@NotNull String path, @NotNull String start, boolean strict, boolean caseSensitive, |
| boolean checkImmediateParent) { |
| final int length1 = path.length(); |
| final int length2 = start.length(); |
| if (length2 == 0) return length1 == 0 ? ThreeState.YES : ThreeState.UNSURE; |
| if (length2 > length1) return ThreeState.NO; |
| if (!path.regionMatches(!caseSensitive, 0, start, 0, length2)) return ThreeState.NO; |
| if (length1 == length2) { |
| return strict ? ThreeState.NO : ThreeState.YES; |
| } |
| char last2 = start.charAt(length2 - 1); |
| int slashOrSeparatorIdx = length2; |
| if (last2 == '/' || last2 == File.separatorChar) { |
| slashOrSeparatorIdx = length2 - 1; |
| } |
| char next1 = path.charAt(slashOrSeparatorIdx); |
| if (next1 == '/' || next1 == File.separatorChar) { |
| if (!checkImmediateParent) return ThreeState.YES; |
| |
| if (slashOrSeparatorIdx == length1 - 1) return ThreeState.YES; |
| int idxNext = path.indexOf(next1, slashOrSeparatorIdx + 1); |
| idxNext = idxNext == -1 ? path.indexOf(next1 == '/' ? '\\' : '/', slashOrSeparatorIdx + 1) : idxNext; |
| return idxNext == -1 ? ThreeState.YES : ThreeState.UNSURE; |
| } |
| else { |
| return ThreeState.NO; |
| } |
| } |
| |
| /** |
| * @param removeProcessor parent, child |
| */ |
| public static <T> Collection<T> removeAncestors(final Collection<T> files, |
| final Convertor<T, String> convertor, |
| final PairProcessor<T, T> removeProcessor) { |
| if (files.isEmpty()) return files; |
| final TreeMap<String, T> paths = new TreeMap<String, T>(); |
| for (T file : files) { |
| final String path = convertor.convert(file); |
| assert path != null; |
| final String canonicalPath = toCanonicalPath(path); |
| paths.put(canonicalPath, file); |
| } |
| final List<Map.Entry<String, T>> ordered = new ArrayList<Map.Entry<String, T>>(paths.entrySet()); |
| final List<T> result = new ArrayList<T>(ordered.size()); |
| result.add(ordered.get(0).getValue()); |
| for (int i = 1; i < ordered.size(); i++) { |
| final Map.Entry<String, T> entry = ordered.get(i); |
| final String child = entry.getKey(); |
| boolean parentNotFound = true; |
| for (int j = i - 1; j >= 0; j--) { |
| // possible parents |
| final String parent = ordered.get(j).getKey(); |
| if (parent == null) continue; |
| if (startsWith(child, parent) && removeProcessor.process(ordered.get(j).getValue(), entry.getValue())) { |
| parentNotFound = false; |
| break; |
| } |
| } |
| if (parentNotFound) { |
| result.add(entry.getValue()); |
| } |
| } |
| return result; |
| } |
| |
| @Nullable |
| public static File getParentFile(@NotNull File file) { |
| return FileUtilRt.getParentFile(file); |
| } |
| |
| @NotNull |
| public static byte[] loadFileBytes(@NotNull File file) throws IOException { |
| byte[] bytes; |
| final InputStream stream = new FileInputStream(file); |
| try { |
| final long len = file.length(); |
| if (len < 0) { |
| throw new IOException("File length reported negative, probably doesn't exist"); |
| } |
| |
| if (isTooLarge(len)) { |
| throw new FileTooBigException("Attempt to load '" + file + "' in memory buffer, file length is " + len + " bytes."); |
| } |
| |
| bytes = loadBytes(stream, (int)len); |
| } |
| finally { |
| stream.close(); |
| } |
| return bytes; |
| } |
| |
| public static boolean processFirstBytes(@NotNull InputStream stream, int length, @NotNull Processor<ByteSequence> processor) |
| throws IOException { |
| final byte[] bytes = BUFFER.get(); |
| assert bytes.length >= length : "Cannot process more than " + bytes.length + " in one call, requested:" + length; |
| |
| int n = stream.read(bytes, 0, length); |
| if (n <= 0) return false; |
| |
| return processor.process(new ByteSequence(bytes, 0, n)); |
| } |
| |
| @NotNull |
| public static byte[] loadFirst(@NotNull InputStream stream, int maxLength) throws IOException { |
| ByteArrayOutputStream buffer = new ByteArrayOutputStream(); |
| final byte[] bytes = BUFFER.get(); |
| while (maxLength > 0) { |
| int n = stream.read(bytes, 0, Math.min(maxLength, bytes.length)); |
| if (n <= 0) break; |
| buffer.write(bytes, 0, n); |
| maxLength -= n; |
| } |
| buffer.close(); |
| return buffer.toByteArray(); |
| } |
| |
| @NotNull |
| public static String loadTextAndClose(@NotNull InputStream stream) throws IOException { |
| //noinspection IOResourceOpenedButNotSafelyClosed |
| return loadTextAndClose(new InputStreamReader(stream)); |
| } |
| |
| @NotNull |
| public static String loadTextAndClose(@NotNull Reader reader) throws IOException { |
| try { |
| return StringFactory.createShared(adaptiveLoadText(reader)); |
| } |
| finally { |
| reader.close(); |
| } |
| } |
| |
| @NotNull |
| public static char[] adaptiveLoadText(@NotNull Reader reader) throws IOException { |
| char[] chars = new char[4096]; |
| List<char[]> buffers = null; |
| int count = 0; |
| int total = 0; |
| while (true) { |
| int n = reader.read(chars, count, chars.length - count); |
| if (n <= 0) break; |
| count += n; |
| if (total > 1024 * 1024 * 10) throw new FileTooBigException("File too big " + reader); |
| total += n; |
| if (count == chars.length) { |
| if (buffers == null) { |
| buffers = new ArrayList<char[]>(); |
| } |
| buffers.add(chars); |
| int newLength = Math.min(1024 * 1024, chars.length * 2); |
| chars = new char[newLength]; |
| count = 0; |
| } |
| } |
| char[] result = new char[total]; |
| if (buffers != null) { |
| for (char[] buffer : buffers) { |
| System.arraycopy(buffer, 0, result, result.length - total, buffer.length); |
| total -= buffer.length; |
| } |
| } |
| System.arraycopy(chars, 0, result, result.length - total, total); |
| return result; |
| } |
| |
| @NotNull |
| public static byte[] adaptiveLoadBytes(@NotNull InputStream stream) throws IOException { |
| byte[] bytes = new byte[4096]; |
| List<byte[]> buffers = null; |
| int count = 0; |
| int total = 0; |
| while (true) { |
| int n = stream.read(bytes, count, bytes.length - count); |
| if (n <= 0) break; |
| count += n; |
| if (total > 1024 * 1024 * 10) throw new FileTooBigException("File too big " + stream); |
| total += n; |
| if (count == bytes.length) { |
| if (buffers == null) { |
| buffers = new ArrayList<byte[]>(); |
| } |
| buffers.add(bytes); |
| int newLength = Math.min(1024 * 1024, bytes.length * 2); |
| bytes = new byte[newLength]; |
| count = 0; |
| } |
| } |
| byte[] result = new byte[total]; |
| if (buffers != null) { |
| for (byte[] buffer : buffers) { |
| System.arraycopy(buffer, 0, result, result.length - total, buffer.length); |
| total -= buffer.length; |
| } |
| } |
| System.arraycopy(bytes, 0, result, result.length - total, total); |
| return result; |
| } |
| |
| @NotNull |
| public static Future<Void> asyncDelete(@NotNull File file) { |
| return asyncDelete(Collections.singleton(file)); |
| } |
| |
| @NotNull |
| public static Future<Void> asyncDelete(@NotNull Collection<File> files) { |
| List<File> tempFiles = new ArrayList<File>(); |
| for (File file : files) { |
| final File tempFile = renameToTempFileOrDelete(file); |
| if (tempFile != null) { |
| tempFiles.add(tempFile); |
| } |
| } |
| if (!tempFiles.isEmpty()) { |
| return startDeletionThread(tempFiles.toArray(new File[tempFiles.size()])); |
| } |
| return new FixedFuture<Void>(null); |
| } |
| |
| private static Future<Void> startDeletionThread(@NotNull final File... tempFiles) { |
| final RunnableFuture<Void> deleteFilesTask = new FutureTask<Void>(new Runnable() { |
| @Override |
| public void run() { |
| final Thread currentThread = Thread.currentThread(); |
| final int priority = currentThread.getPriority(); |
| currentThread.setPriority(Thread.MIN_PRIORITY); |
| try { |
| for (File tempFile : tempFiles) { |
| delete(tempFile); |
| } |
| } |
| finally { |
| currentThread.setPriority(priority); |
| } |
| } |
| }, null); |
| |
| try { |
| // attempt to execute on pooled thread |
| final Class<?> aClass = Class.forName("com.intellij.openapi.application.ApplicationManager"); |
| final Method getApplicationMethod = aClass.getMethod("getApplication"); |
| final Object application = getApplicationMethod.invoke(null); |
| final Method executeOnPooledThreadMethod = application.getClass().getMethod("executeOnPooledThread", Runnable.class); |
| executeOnPooledThreadMethod.invoke(application, deleteFilesTask); |
| } |
| catch (Exception ignored) { |
| new Thread(deleteFilesTask, "File deletion thread").start(); |
| } |
| return deleteFilesTask; |
| } |
| |
| @Nullable |
| private static File renameToTempFileOrDelete(@NotNull File file) { |
| final File tempDir = new File(getTempDirectory()); |
| boolean isSameDrive = true; |
| if (SystemInfo.isWindows) { |
| String tempDirDrive = tempDir.getAbsolutePath().substring(0, 2); |
| String fileDrive = file.getAbsolutePath().substring(0, 2); |
| isSameDrive = tempDirDrive.equalsIgnoreCase(fileDrive); |
| } |
| |
| if (isSameDrive) { |
| // the optimization is reasonable only if destination dir is located on the same drive |
| final String originalFileName = file.getName(); |
| File tempFile = getTempFile(originalFileName, tempDir); |
| if (file.renameTo(tempFile)) { |
| return tempFile; |
| } |
| } |
| |
| delete(file); |
| |
| return null; |
| } |
| |
| private static File getTempFile(@NotNull String originalFileName, @NotNull File parent) { |
| int randomSuffix = (int)(System.currentTimeMillis() % 1000); |
| for (int i = randomSuffix; ; i++) { |
| @NonNls String name = "___" + originalFileName + i + ASYNC_DELETE_EXTENSION; |
| File tempFile = new File(parent, name); |
| if (!tempFile.exists()) return tempFile; |
| } |
| } |
| |
| public static boolean delete(@NotNull File file) { |
| if (SystemInfo.isWindows) { |
| File tempFile = findSequentNonexistentFile(file.getParentFile(), file.getName(), ""); |
| if (file.renameTo(tempFile)) { |
| file = tempFile; |
| } |
| } |
| |
| return doDelete(file); |
| } |
| |
| private static boolean doDelete(File file) { |
| FileAttributes attributes = FileSystemUtil.getAttributes(file); |
| if (attributes == null) return true; |
| |
| if (attributes.isDirectory() && !attributes.isSymLink()) { |
| File[] files = file.listFiles(); |
| if (files != null) { |
| for (File child : files) { |
| if (!doDelete(child)) return false; |
| } |
| } |
| } |
| |
| return deleteFile(file); |
| } |
| |
| public static boolean createParentDirs(@NotNull File file) { |
| return FileUtilRt.createParentDirs(file); |
| } |
| |
| public static boolean createDirectory(@NotNull File path) { |
| return FileUtilRt.createDirectory(path); |
| } |
| |
| public static boolean createIfDoesntExist(@NotNull File file) { |
| return FileUtilRt.createIfNotExists(file); |
| } |
| |
| public static boolean ensureCanCreateFile(@NotNull File file) { |
| return FileUtilRt.ensureCanCreateFile(file); |
| } |
| |
| public static void copy(@NotNull File fromFile, @NotNull File toFile) throws IOException { |
| performCopy(fromFile, toFile, true); |
| } |
| |
| public static void copyContent(@NotNull File fromFile, @NotNull File toFile) throws IOException { |
| performCopy(fromFile, toFile, false); |
| } |
| |
| private static void performCopy(@NotNull File fromFile, @NotNull File toFile, final boolean syncTimestamp) throws IOException { |
| final FileOutputStream fos; |
| try { |
| fos = openOutputStream(toFile); |
| } |
| catch (IOException e) { |
| if (SystemInfo.isWindows && e.getMessage() != null && e.getMessage().contains("denied") && |
| WinUACTemporaryFix.nativeCopy(fromFile, toFile, syncTimestamp)) { |
| return; |
| } |
| throw e; |
| } |
| |
| try { |
| final FileInputStream fis = new FileInputStream(fromFile); |
| try { |
| copy(fis, fos); |
| } |
| finally { |
| fis.close(); |
| } |
| } |
| finally { |
| fos.close(); |
| } |
| |
| if (syncTimestamp) { |
| final long timeStamp = fromFile.lastModified(); |
| if (timeStamp < 0) { |
| LOG.warn("Invalid timestamp " + timeStamp + " of '" + fromFile + "'"); |
| } |
| else if (!toFile.setLastModified(timeStamp)) { |
| LOG.warn("Unable to set timestamp " + timeStamp + " to '" + toFile + "'"); |
| } |
| } |
| |
| if (SystemInfo.isUnix && fromFile.canExecute()) { |
| FileSystemUtil.clonePermissions(fromFile.getPath(), toFile.getPath()); |
| } |
| } |
| |
| private static FileOutputStream openOutputStream(@NotNull final File file) throws IOException { |
| try { |
| return new FileOutputStream(file); |
| } |
| catch (FileNotFoundException e) { |
| final File parentFile = file.getParentFile(); |
| if (parentFile == null) { |
| throw new IOException("Parent file is null for " + file.getPath(), e); |
| } |
| createParentDirs(file); |
| return new FileOutputStream(file); |
| } |
| } |
| |
| public static void copy(@NotNull InputStream inputStream, @NotNull OutputStream outputStream) throws IOException { |
| FileUtilRt.copy(inputStream, outputStream); |
| } |
| |
| public static void copy(@NotNull InputStream inputStream, int maxSize, @NotNull OutputStream outputStream) throws IOException { |
| final byte[] buffer = BUFFER.get(); |
| int toRead = maxSize; |
| while (toRead > 0) { |
| int read = inputStream.read(buffer, 0, Math.min(buffer.length, toRead)); |
| if (read < 0) break; |
| toRead -= read; |
| outputStream.write(buffer, 0, read); |
| } |
| } |
| |
| public static void copyDir(@NotNull File fromDir, @NotNull File toDir) throws IOException { |
| copyDir(fromDir, toDir, true); |
| } |
| |
| /** |
| * Copies content of {@code fromDir} to {@code toDir}. |
| * It's equivalent to "cp -r fromDir/* toDir" unix command. |
| * |
| * @param fromDir source directory |
| * @param toDir destination directory |
| * @throws IOException in case of any IO troubles |
| */ |
| public static void copyDirContent(@NotNull File fromDir, @NotNull File toDir) throws IOException { |
| File[] children = ObjectUtils.notNull(fromDir.listFiles(), ArrayUtil.EMPTY_FILE_ARRAY); |
| for (File child : children) { |
| File target = new File(toDir, child.getName()); |
| if (child.isFile()) { |
| copy(child, target); |
| } |
| else { |
| copyDir(child, target, true); |
| } |
| } |
| } |
| |
| public static void copyDir(@NotNull File fromDir, @NotNull File toDir, boolean copySystemFiles) throws IOException { |
| copyDir(fromDir, toDir, copySystemFiles ? null : new FileFilter() { |
| @Override |
| public boolean accept(File file) { |
| return !StringUtil.startsWithChar(file.getName(), '.'); |
| } |
| }); |
| } |
| |
| public static void copyDir(@NotNull File fromDir, @NotNull File toDir, @Nullable final FileFilter filter) throws IOException { |
| ensureExists(toDir); |
| if (isAncestor(fromDir, toDir, true)) { |
| LOG.error(fromDir.getAbsolutePath() + " is ancestor of " + toDir + ". Can't copy to itself."); |
| return; |
| } |
| File[] files = fromDir.listFiles(); |
| if (files == null) throw new IOException(CommonBundle.message("exception.directory.is.invalid", fromDir.getPath())); |
| if (!fromDir.canRead()) throw new IOException(CommonBundle.message("exception.directory.is.not.readable", fromDir.getPath())); |
| for (File file : files) { |
| if (filter != null && !filter.accept(file)) { |
| continue; |
| } |
| if (file.isDirectory()) { |
| copyDir(file, new File(toDir, file.getName()), filter); |
| } |
| else { |
| copy(file, new File(toDir, file.getName())); |
| } |
| } |
| } |
| |
| public static void ensureExists(@NotNull File dir) throws IOException { |
| if (!dir.exists() && !dir.mkdirs()) { |
| throw new IOException(CommonBundle.message("exception.directory.can.not.create", dir.getPath())); |
| } |
| } |
| |
| @NotNull |
| public static String getNameWithoutExtension(@NotNull File file) { |
| return getNameWithoutExtension(file.getName()); |
| } |
| |
| @NotNull |
| public static String getNameWithoutExtension(@NotNull String name) { |
| return FileUtilRt.getNameWithoutExtension(name); |
| } |
| |
| public static String createSequentFileName(@NotNull File aParentFolder, @NotNull @NonNls String aFilePrefix, @NotNull String aExtension) { |
| return findSequentNonexistentFile(aParentFolder, aFilePrefix, aExtension).getName(); |
| } |
| |
| public static File findSequentNonexistentFile(@NotNull File parentFolder, @NotNull String filePrefix, @NotNull String extension) { |
| int postfix = 0; |
| String ext = extension.isEmpty() ? "" : '.' + extension; |
| File candidate = new File(parentFolder, filePrefix + ext); |
| while (candidate.exists()) { |
| postfix++; |
| candidate = new File(parentFolder, filePrefix + Integer.toString(postfix) + ext); |
| } |
| return candidate; |
| } |
| |
| @NotNull |
| public static String toSystemDependentName(@NonNls @NotNull String aFileName) { |
| return FileUtilRt.toSystemDependentName(aFileName); |
| } |
| |
| @NotNull |
| public static String toSystemIndependentName(@NonNls @NotNull String aFileName) { |
| return FileUtilRt.toSystemIndependentName(aFileName); |
| } |
| |
| @NotNull |
| public static String nameToCompare(@NonNls @NotNull String name) { |
| return (SystemInfo.isFileSystemCaseSensitive ? name : name.toLowerCase()).replace('\\', '/'); |
| } |
| |
| /** |
| * Converts given path to canonical representation by eliminating '.'s, traversing '..'s, and omitting duplicate separators. |
| * Please note that this method is symlink-unfriendly (i.e. result of "/path/to/link/../next" most probably will differ from |
| * what {@link java.io.File#getCanonicalPath()} will return) - so use with care. |
| */ |
| @Contract("null -> null") |
| public static String toCanonicalPath(@Nullable String path) { |
| return toCanonicalPath(path, File.separatorChar, true); |
| } |
| |
| @Contract("null, _ -> null") |
| public static String toCanonicalPath(@Nullable String path, char separatorChar) { |
| return toCanonicalPath(path, separatorChar, true); |
| } |
| |
| @Contract("null -> null") |
| public static String toCanonicalUriPath(@Nullable String path) { |
| return toCanonicalPath(path, '/', false); |
| } |
| |
| @Contract("null, _, _ -> null") |
| private static String toCanonicalPath(@Nullable String path, char separatorChar, boolean removeLastSlash) { |
| if (path == null || path.isEmpty()) { |
| return path; |
| } |
| else if (".".equals(path)) { |
| return ""; |
| } |
| |
| path = path.replace(separatorChar, '/'); |
| if (path.indexOf('/') == -1) { |
| return path; |
| } |
| |
| StringBuilder result = new StringBuilder(path.length()); |
| int start = processRoot(path, result), dots = 0; |
| boolean separator = true; |
| |
| for (int i = start; i < path.length(); ++i) { |
| char c = path.charAt(i); |
| if (c == '/') { |
| if (!separator) { |
| processDots(result, dots, start); |
| dots = 0; |
| } |
| separator = true; |
| } |
| else if (c == '.') { |
| if (separator || dots > 0) { |
| ++dots; |
| } |
| else { |
| result.append('.'); |
| } |
| separator = false; |
| } |
| else { |
| if (dots > 0) { |
| StringUtil.repeatSymbol(result, '.', dots); |
| dots = 0; |
| } |
| result.append(c); |
| separator = false; |
| } |
| } |
| |
| if (dots > 0) { |
| processDots(result, dots, start); |
| } |
| |
| int lastChar = result.length() - 1; |
| if (removeLastSlash && lastChar >= 0 && result.charAt(lastChar) == '/' && lastChar > start) { |
| result.deleteCharAt(lastChar); |
| } |
| |
| return result.toString(); |
| } |
| |
| private static int processRoot(String path, StringBuilder result) { |
| if (SystemInfo.isWindows && path.length() > 1 && path.charAt(0) == '/' && path.charAt(1) == '/') { |
| result.append("//"); |
| |
| int hostStart = 2; |
| while (hostStart < path.length() && path.charAt(hostStart) == '/') hostStart++; |
| if (hostStart == path.length()) return hostStart; |
| int hostEnd = path.indexOf('/', hostStart); |
| if (hostEnd < 0) hostEnd = path.length(); |
| result.append(path, hostStart, hostEnd); |
| result.append('/'); |
| |
| int shareStart = hostEnd; |
| while (shareStart < path.length() && path.charAt(shareStart) == '/') shareStart++; |
| if (shareStart == path.length()) return shareStart; |
| int shareEnd = path.indexOf('/', shareStart); |
| if (shareEnd < 0) shareEnd = path.length(); |
| result.append(path, shareStart, shareEnd); |
| result.append('/'); |
| |
| return shareEnd; |
| } |
| else if (path.length() > 0 && path.charAt(0) == '/') { |
| result.append('/'); |
| return 1; |
| } |
| else if (path.length() > 2 && path.charAt(1) == ':' && path.charAt(2) == '/') { |
| result.append(path, 0, 3); |
| return 3; |
| } |
| else { |
| return 0; |
| } |
| } |
| |
| private static void processDots(StringBuilder result, int dots, int start) { |
| if (dots == 2) { |
| int pos = -1; |
| if (!StringUtil.endsWith(result, "/../") && !StringUtil.equals(result, "../")) { |
| pos = StringUtil.lastIndexOf(result, '/', start, result.length() - 1); |
| if (pos >= 0) { |
| ++pos; // separator found, trim to next char |
| } |
| else if (start > 0) { |
| pos = start; // path is absolute, trim to root ('/..' -> '/') |
| } |
| else if (result.length() > 0) { |
| pos = 0; // path is relative, trim to default ('a/..' -> '') |
| } |
| } |
| if (pos >= 0) { |
| result.delete(pos, result.length()); |
| } |
| else { |
| result.append("../"); // impossible to traverse, keep as-is |
| } |
| } |
| else if (dots != 1) { |
| StringUtil.repeatSymbol(result, '.', dots); |
| result.append('/'); |
| } |
| } |
| |
| /** |
| * converts back slashes to forward slashes |
| * removes double slashes inside the path, e.g. "x/y//z" => "x/y/z" |
| */ |
| @NotNull |
| public static String normalize(@NotNull String path) { |
| int start = 0; |
| boolean separator = false; |
| if (SystemInfo.isWindows) { |
| if (path.startsWith("//")) { |
| start = 2; |
| separator = true; |
| } |
| else if (path.startsWith("\\\\")) { |
| return normalizeTail(0, path, false); |
| } |
| } |
| |
| for (int i = start; i < path.length(); ++i) { |
| final char c = path.charAt(i); |
| if (c == '/') { |
| if (separator) { |
| return normalizeTail(i, path, true); |
| } |
| separator = true; |
| } |
| else if (c == '\\') { |
| return normalizeTail(i, path, separator); |
| } |
| else { |
| separator = false; |
| } |
| } |
| |
| return path; |
| } |
| |
| @NotNull |
| private static String normalizeTail(int prefixEnd, @NotNull String path, boolean separator) { |
| final StringBuilder result = new StringBuilder(path.length()); |
| result.append(path, 0, prefixEnd); |
| int start = prefixEnd; |
| if (start==0 && SystemInfo.isWindows && (path.startsWith("//") || path.startsWith("\\\\"))) { |
| start = 2; |
| result.append("//"); |
| separator = true; |
| } |
| |
| for (int i = start; i < path.length(); ++i) { |
| final char c = path.charAt(i); |
| if (c == '/' || c == '\\') { |
| if (!separator) result.append('/'); |
| separator = true; |
| } |
| else { |
| result.append(c); |
| separator = false; |
| } |
| } |
| |
| return result.toString(); |
| } |
| |
| @NotNull |
| public static String unquote(@NotNull String urlString) { |
| urlString = urlString.replace('/', File.separatorChar); |
| return URLUtil.unescapePercentSequences(urlString); |
| } |
| |
| public static boolean isFilePathAcceptable(@NotNull File root, @Nullable FileFilter fileFilter) { |
| if (fileFilter == null) return true; |
| File file = root; |
| do { |
| if (!fileFilter.accept(file)) return false; |
| file = file.getParentFile(); |
| } |
| while (file != null); |
| return true; |
| } |
| |
| public static void rename(@NotNull File source, @NotNull File target) throws IOException { |
| if (source.renameTo(target)) return; |
| if (!source.exists()) return; |
| |
| copy(source, target); |
| delete(source); |
| } |
| |
| public static boolean filesEqual(@Nullable File file1, @Nullable File file2) { |
| // on MacOS java.io.File.equals() is incorrectly case-sensitive |
| return pathsEqual(file1 == null ? null : file1.getPath(), |
| file2 == null ? null : file2.getPath()); |
| } |
| |
| public static boolean pathsEqual(@Nullable String path1, @Nullable String path2) { |
| if (path1 == path2) return true; |
| if (path1 == null || path2 == null) return false; |
| |
| path1 = toCanonicalPath(path1); |
| path2 = toCanonicalPath(path2); |
| return PATH_HASHING_STRATEGY.equals(path1, path2); |
| } |
| |
| /** |
| * optimized version of pathsEqual - it only compares pure names, without file separators |
| */ |
| public static boolean namesEqual(@Nullable String name1, @Nullable String name2) { |
| if (name1 == name2) return true; |
| if (name1 == null || name2 == null) return false; |
| |
| return PATH_HASHING_STRATEGY.equals(name1, name2); |
| } |
| |
| public static int compareFiles(@Nullable File file1, @Nullable File file2) { |
| return comparePaths(file1 == null ? null : file1.getPath(), file2 == null ? null : file2.getPath()); |
| } |
| |
| public static int comparePaths(@Nullable String path1, @Nullable String path2) { |
| path1 = path1 == null ? null : toSystemIndependentName(path1); |
| path2 = path2 == null ? null : toSystemIndependentName(path2); |
| return StringUtil.compare(path1, path2, !SystemInfo.isFileSystemCaseSensitive); |
| } |
| |
| public static int fileHashCode(@Nullable File file) { |
| return pathHashCode(file == null ? null : file.getPath()); |
| } |
| |
| public static int pathHashCode(@Nullable String path) { |
| return StringUtil.isEmpty(path) ? 0 : PATH_HASHING_STRATEGY.computeHashCode(toCanonicalPath(path)); |
| } |
| |
| /** |
| * @deprecated this method returns extension converted to lower case, this may not be correct for case-sensitive FS. |
| * Use {@link FileUtilRt#getExtension(String)} instead to get the unchanged extension. |
| * If you need to check whether a file has a specified extension use {@link FileUtilRt#extensionEquals(String, String)} |
| */ |
| @NotNull |
| public static String getExtension(@NotNull String fileName) { |
| return FileUtilRt.getExtension(fileName).toLowerCase(); |
| } |
| |
| @NotNull |
| public static String resolveShortWindowsName(@NotNull String path) throws IOException { |
| return SystemInfo.isWindows && StringUtil.containsChar(path, '~') ? new File(path).getCanonicalPath() : path; |
| } |
| |
| public static void collectMatchedFiles(@NotNull File root, @NotNull Pattern pattern, @NotNull List<File> outFiles) { |
| collectMatchedFiles(root, root, pattern, outFiles); |
| } |
| |
| private static void collectMatchedFiles(@NotNull File absoluteRoot, |
| @NotNull File root, |
| @NotNull Pattern pattern, |
| @NotNull List<File> files) { |
| final File[] dirs = root.listFiles(); |
| if (dirs == null) return; |
| for (File dir : dirs) { |
| if (dir.isFile()) { |
| final String relativePath = getRelativePath(absoluteRoot, dir); |
| if (relativePath != null) { |
| final String path = toSystemIndependentName(relativePath); |
| if (pattern.matcher(path).matches()) { |
| files.add(dir); |
| } |
| } |
| } |
| else { |
| collectMatchedFiles(absoluteRoot, dir, pattern, files); |
| } |
| } |
| } |
| |
| @RegExp |
| @NotNull |
| public static String convertAntToRegexp(@NotNull String antPattern) { |
| return convertAntToRegexp(antPattern, true); |
| } |
| |
| /** |
| * @param antPattern ant-style path pattern |
| * @return java regexp pattern. |
| * Note that no matter whether forward or backward slashes were used in the antPattern |
| * the returned regexp pattern will use forward slashes ('/') as file separators. |
| * Paths containing windows-style backslashes must be converted before matching against the resulting regexp |
| * @see com.intellij.openapi.util.io.FileUtil#toSystemIndependentName |
| */ |
| @RegExp |
| @NotNull |
| public static String convertAntToRegexp(@NotNull String antPattern, boolean ignoreStartingSlash) { |
| final StringBuilder builder = new StringBuilder(); |
| int asteriskCount = 0; |
| boolean recursive = true; |
| final int start = |
| ignoreStartingSlash && (StringUtil.startsWithChar(antPattern, '/') || StringUtil.startsWithChar(antPattern, '\\')) ? 1 : 0; |
| for (int idx = start; idx < antPattern.length(); idx++) { |
| final char ch = antPattern.charAt(idx); |
| |
| if (ch == '*') { |
| asteriskCount++; |
| continue; |
| } |
| |
| final boolean foundRecursivePattern = recursive && asteriskCount == 2 && (ch == '/' || ch == '\\'); |
| final boolean asterisksFound = asteriskCount > 0; |
| |
| asteriskCount = 0; |
| recursive = ch == '/' || ch == '\\'; |
| |
| if (foundRecursivePattern) { |
| builder.append("(?:[^/]+/)*?"); |
| continue; |
| } |
| |
| if (asterisksFound) { |
| builder.append("[^/]*?"); |
| } |
| |
| if (ch == '(' || |
| ch == ')' || |
| ch == '[' || |
| ch == ']' || |
| ch == '^' || |
| ch == '$' || |
| ch == '.' || |
| ch == '{' || |
| ch == '}' || |
| ch == '+' || |
| ch == '|') { |
| // quote regexp-specific symbols |
| builder.append('\\').append(ch); |
| continue; |
| } |
| if (ch == '?') { |
| builder.append("[^/]{1}"); |
| continue; |
| } |
| if (ch == '\\') { |
| builder.append('/'); |
| continue; |
| } |
| builder.append(ch); |
| } |
| |
| // handle ant shorthand: mypackage/test/ is interpreted as if it were mypackage/test/** |
| final boolean isTrailingSlash = builder.length() > 0 && builder.charAt(builder.length() - 1) == '/'; |
| if (asteriskCount == 0 && isTrailingSlash || recursive && asteriskCount == 2) { |
| if (isTrailingSlash) { |
| builder.setLength(builder.length() - 1); |
| } |
| if (builder.length() == 0) { |
| builder.append(".*"); |
| } |
| else { |
| builder.append("(?:$|/.+)"); |
| } |
| } |
| else if (asteriskCount > 0) { |
| builder.append("[^/]*?"); |
| } |
| return builder.toString(); |
| } |
| |
| public static boolean moveDirWithContent(@NotNull File fromDir, @NotNull File toDir) { |
| if (!toDir.exists()) return fromDir.renameTo(toDir); |
| |
| File[] files = fromDir.listFiles(); |
| if (files == null) return false; |
| |
| boolean success = true; |
| |
| for (File fromFile : files) { |
| File toFile = new File(toDir, fromFile.getName()); |
| success = success && fromFile.renameTo(toFile); |
| } |
| //noinspection ResultOfMethodCallIgnored |
| fromDir.delete(); |
| |
| return success; |
| } |
| |
| /** |
| * Has duplicate: {@link com.intellij.coverage.listeners.CoverageListener#sanitize(java.lang.String, java.lang.String)} |
| * as FileUtil is not available in client's vm |
| */ |
| @NotNull |
| public static String sanitizeFileName(@NotNull String name) { |
| StringBuilder result = new StringBuilder(); |
| |
| for (int i = 0; i < name.length(); i++) { |
| final char ch = name.charAt(i); |
| |
| if (ch > 0 && ch < 255) { |
| if (Character.isLetterOrDigit(ch)) { |
| result.append(ch); |
| } |
| else { |
| result.append("_"); |
| } |
| } |
| } |
| |
| return result.toString(); |
| } |
| |
| public static boolean canExecute(@NotNull File file) { |
| return file.canExecute(); |
| } |
| |
| public static void setReadOnlyAttribute(@NotNull String path, boolean readOnlyFlag) { |
| final boolean writableFlag = !readOnlyFlag; |
| final File file = new File(path); |
| if (!file.setWritable(writableFlag) && file.canWrite() != writableFlag) { |
| LOG.warn("Can't set writable attribute of '" + path + "' to " + readOnlyFlag); |
| } |
| } |
| |
| public static void appendToFile(@NotNull File file, @NotNull String text) throws IOException { |
| writeToFile(file, text.getBytes("UTF-8"), true); |
| } |
| |
| public static void writeToFile(@NotNull File file, @NotNull byte[] text) throws IOException { |
| writeToFile(file, text, false); |
| } |
| |
| public static void writeToFile(@NotNull File file, @NotNull String text) throws IOException { |
| writeToFile(file, text.getBytes("UTF-8"), false); |
| } |
| |
| public static void writeToFile(@NotNull File file, @NotNull byte[] text, int off, int len) throws IOException { |
| writeToFile(file, text, off, len, false); |
| } |
| |
| public static void writeToFile(@NotNull File file, @NotNull byte[] text, boolean append) throws IOException { |
| writeToFile(file, text, 0, text.length, append); |
| } |
| |
| private static void writeToFile(@NotNull File file, @NotNull byte[] text, int off, int len, boolean append) throws IOException { |
| createParentDirs(file); |
| |
| OutputStream stream = new FileOutputStream(file, append); |
| try { |
| stream.write(text, off, len); |
| } |
| finally { |
| stream.close(); |
| } |
| } |
| |
| public static boolean processFilesRecursively(@NotNull File root, @NotNull Processor<File> processor) { |
| return processFilesRecursively(root, processor, null); |
| } |
| |
| public static boolean processFilesRecursively(@NotNull File root, @NotNull Processor<File> processor, |
| @Nullable final Processor<File> directoryFilter) { |
| final LinkedList<File> queue = new LinkedList<File>(); |
| queue.add(root); |
| while (!queue.isEmpty()) { |
| final File file = queue.removeFirst(); |
| if (!processor.process(file)) return false; |
| if (directoryFilter != null && (!file.isDirectory() || !directoryFilter.process(file))) continue; |
| |
| final File[] children = file.listFiles(); |
| if (children != null) { |
| ContainerUtil.addAll(queue, children); |
| } |
| } |
| return true; |
| } |
| |
| @Nullable |
| public static File findFirstThatExist(@NotNull String... paths) { |
| for (String path : paths) { |
| if (!StringUtil.isEmptyOrSpaces(path)) { |
| File file = new File(toSystemDependentName(path)); |
| if (file.exists()) return file; |
| } |
| } |
| |
| return null; |
| } |
| |
| @NotNull |
| public static List<File> findFilesByMask(@NotNull Pattern pattern, @NotNull File dir) { |
| final ArrayList<File> found = new ArrayList<File>(); |
| final File[] files = dir.listFiles(); |
| if (files != null) { |
| for (File file : files) { |
| if (file.isDirectory()) { |
| found.addAll(findFilesByMask(pattern, file)); |
| } |
| else if (pattern.matcher(file.getName()).matches()) { |
| found.add(file); |
| } |
| } |
| } |
| return found; |
| } |
| |
| @NotNull |
| public static List<File> findFilesOrDirsByMask(@NotNull Pattern pattern, @NotNull File dir) { |
| final ArrayList<File> found = new ArrayList<File>(); |
| final File[] files = dir.listFiles(); |
| if (files != null) { |
| for (File file : files) { |
| if (pattern.matcher(file.getName()).matches()) { |
| found.add(file); |
| } |
| if (file.isDirectory()) { |
| found.addAll(findFilesOrDirsByMask(pattern, file)); |
| } |
| } |
| } |
| return found; |
| } |
| |
| /** |
| * Returns empty string for empty path. |
| * First checks whether provided path is a path of a file with sought-for name. |
| * Unless found, checks if provided file was a directory. In this case checks existence |
| * of child files with given names in order "as provided". Finally checks filename among |
| * brother-files of provided. Returns null if nothing found. |
| * |
| * @return path of the first of found files or empty string or null. |
| */ |
| @Nullable |
| public static String findFileInProvidedPath(String providedPath, String... fileNames) { |
| if (StringUtil.isEmpty(providedPath)) { |
| return ""; |
| } |
| |
| File providedFile = new File(providedPath); |
| if (providedFile.exists()) { |
| String name = providedFile.getName(); |
| for (String fileName : fileNames) { |
| if (name.equals(fileName)) { |
| return toSystemDependentName(providedFile.getPath()); |
| } |
| } |
| } |
| |
| if (providedFile.isDirectory()) { //user chose folder with file |
| for (String fileName : fileNames) { |
| File file = new File(providedFile, fileName); |
| if (fileName.equals(file.getName()) && file.exists()) { |
| return toSystemDependentName(file.getPath()); |
| } |
| } |
| } |
| |
| providedFile = providedFile.getParentFile(); //users chose wrong file in same directory |
| if (providedFile != null && providedFile.exists()) { |
| for (String fileName : fileNames) { |
| File file = new File(providedFile, fileName); |
| if (fileName.equals(file.getName()) && file.exists()) { |
| return toSystemDependentName(file.getPath()); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| public static boolean isAbsolutePlatformIndependent(@NotNull String path) { |
| return isUnixAbsolutePath(path) || isWindowsAbsolutePath(path); |
| } |
| |
| public static boolean isUnixAbsolutePath(@NotNull String path) { |
| return path.startsWith("/"); |
| } |
| |
| public static boolean isWindowsAbsolutePath(@NotNull String pathString) { |
| return pathString.length() >= 2 && Character.isLetter(pathString.charAt(0)) && pathString.charAt(1) == ':'; |
| } |
| |
| @Contract("null -> null; !null -> !null") |
| public static String getLocationRelativeToUserHome(@Nullable String path) { |
| return getLocationRelativeToUserHome(path, true); |
| } |
| |
| @Contract("null,_ -> null; !null,_ -> !null") |
| public static String getLocationRelativeToUserHome(@Nullable String path, boolean unixOnly) { |
| if (path == null) return null; |
| |
| if (SystemInfo.isUnix || !unixOnly) { |
| File projectDir = new File(path); |
| File userHomeDir = new File(SystemProperties.getUserHome()); |
| if (isAncestor(userHomeDir, projectDir, true)) { |
| return '~' + File.separator + getRelativePath(userHomeDir, projectDir); |
| } |
| } |
| |
| return path; |
| } |
| |
| @NotNull |
| public static String expandUserHome(@NotNull String path) { |
| if (path.startsWith("~/") || path.startsWith("~\\")) { |
| path = SystemProperties.getUserHome() + path.substring(1); |
| } |
| return path; |
| } |
| |
| @NotNull |
| public static File[] notNullize(@Nullable File[] files) { |
| return notNullize(files, ArrayUtil.EMPTY_FILE_ARRAY); |
| } |
| |
| @NotNull |
| public static File[] notNullize(@Nullable File[] files, @NotNull File[] defaultFiles) { |
| return files == null ? defaultFiles : files; |
| } |
| |
| public static boolean isHashBangLine(CharSequence firstCharsIfText, String marker) { |
| if (firstCharsIfText == null) { |
| return false; |
| } |
| final int lineBreak = StringUtil.indexOf(firstCharsIfText, '\n'); |
| if (lineBreak < 0) { |
| return false; |
| } |
| String firstLine = firstCharsIfText.subSequence(0, lineBreak).toString(); |
| if (!firstLine.startsWith("#!")) { |
| return false; |
| } |
| return firstLine.contains(marker); |
| } |
| |
| @NotNull |
| public static File createTempDirectory(@NotNull @NonNls String prefix, @Nullable @NonNls String suffix) throws IOException { |
| return FileUtilRt.createTempDirectory(prefix, suffix); |
| } |
| |
| @NotNull |
| public static File createTempDirectory(@NotNull @NonNls String prefix, @Nullable @NonNls String suffix, boolean deleteOnExit) |
| throws IOException { |
| return FileUtilRt.createTempDirectory(prefix, suffix, deleteOnExit); |
| } |
| |
| @NotNull |
| public static File createTempDirectory(@NotNull File dir, @NotNull @NonNls String prefix, @Nullable @NonNls String suffix) |
| throws IOException { |
| return FileUtilRt.createTempDirectory(dir, prefix, suffix); |
| } |
| |
| @NotNull |
| public static File createTempDirectory(@NotNull File dir, |
| @NotNull @NonNls String prefix, |
| @Nullable @NonNls String suffix, |
| boolean deleteOnExit) throws IOException { |
| return FileUtilRt.createTempDirectory(dir, prefix, suffix, deleteOnExit); |
| } |
| |
| @NotNull |
| public static File createTempFile(@NotNull @NonNls String prefix, @Nullable @NonNls String suffix) throws IOException { |
| return FileUtilRt.createTempFile(prefix, suffix); |
| } |
| |
| @NotNull |
| public static File createTempFile(@NotNull @NonNls String prefix, @Nullable @NonNls String suffix, boolean deleteOnExit) |
| throws IOException { |
| return FileUtilRt.createTempFile(prefix, suffix, deleteOnExit); |
| } |
| |
| @NotNull |
| public static File createTempFile(@NonNls File dir, @NotNull @NonNls String prefix, @Nullable @NonNls String suffix) throws IOException { |
| return FileUtilRt.createTempFile(dir, prefix, suffix); |
| } |
| |
| @NotNull |
| public static File createTempFile(@NonNls File dir, @NotNull @NonNls String prefix, @Nullable @NonNls String suffix, boolean create) |
| throws IOException { |
| return FileUtilRt.createTempFile(dir, prefix, suffix, create); |
| } |
| |
| @NotNull |
| public static File createTempFile(@NonNls File dir, |
| @NotNull @NonNls String prefix, |
| @Nullable @NonNls String suffix, |
| boolean create, |
| boolean deleteOnExit) throws IOException { |
| return FileUtilRt.createTempFile(dir, prefix, suffix, create, deleteOnExit); |
| } |
| |
| @NotNull |
| public static String getTempDirectory() { |
| return FileUtilRt.getTempDirectory(); |
| } |
| |
| @TestOnly |
| public static void resetCanonicalTempPathCache(final String tempPath) { |
| FileUtilRt.resetCanonicalTempPathCache(tempPath); |
| } |
| |
| @NotNull |
| public static File generateRandomTemporaryPath() throws IOException { |
| return FileUtilRt.generateRandomTemporaryPath(); |
| } |
| |
| public static void setExecutableAttribute(@NotNull String path, boolean executableFlag) throws IOException { |
| FileUtilRt.setExecutableAttribute(path, executableFlag); |
| } |
| |
| public static void setLastModified(@NotNull File file, long timeStamp) throws IOException { |
| if (!file.setLastModified(timeStamp)) { |
| LOG.warn(file.getPath()); |
| } |
| } |
| |
| @NotNull |
| public static String loadFile(@NotNull File file) throws IOException { |
| return FileUtilRt.loadFile(file); |
| } |
| |
| @NotNull |
| public static String loadFile(@NotNull File file, boolean convertLineSeparators) throws IOException { |
| return FileUtilRt.loadFile(file, convertLineSeparators); |
| } |
| |
| @NotNull |
| public static String loadFile(@NotNull File file, @Nullable @NonNls String encoding) throws IOException { |
| return FileUtilRt.loadFile(file, encoding); |
| } |
| |
| @NotNull |
| public static String loadFile(@NotNull File file, @Nullable @NonNls String encoding, boolean convertLineSeparators) throws IOException { |
| return FileUtilRt.loadFile(file, encoding, convertLineSeparators); |
| } |
| |
| @NotNull |
| public static char[] loadFileText(@NotNull File file) throws IOException { |
| return FileUtilRt.loadFileText(file); |
| } |
| |
| @NotNull |
| public static char[] loadFileText(@NotNull File file, @Nullable @NonNls String encoding) throws IOException { |
| return FileUtilRt.loadFileText(file, encoding); |
| } |
| |
| @NotNull |
| public static char[] loadText(@NotNull Reader reader, int length) throws IOException { |
| return FileUtilRt.loadText(reader, length); |
| } |
| |
| @NotNull |
| public static List<String> loadLines(@NotNull File file) throws IOException { |
| return FileUtilRt.loadLines(file); |
| } |
| |
| @NotNull |
| public static List<String> loadLines(@NotNull File file, @Nullable @NonNls String encoding) throws IOException { |
| return FileUtilRt.loadLines(file, encoding); |
| } |
| |
| @NotNull |
| public static List<String> loadLines(@NotNull String path) throws IOException { |
| return FileUtilRt.loadLines(path); |
| } |
| |
| @NotNull |
| public static List<String> loadLines(@NotNull String path, @Nullable @NonNls String encoding) throws IOException { |
| return FileUtilRt.loadLines(path, encoding); |
| } |
| |
| @NotNull |
| public static List<String> loadLines(@NotNull BufferedReader reader) throws IOException { |
| return FileUtilRt.loadLines(reader); |
| } |
| |
| /** @deprecated unclear closing policy, do not use (to remove in IDEA 14) */ |
| @SuppressWarnings({"UnusedDeclaration", "deprecation"}) |
| public static List<String> loadLines(@NotNull InputStream stream) throws IOException { |
| return loadLines(new InputStreamReader(stream)); |
| } |
| |
| /** @deprecated unclear closing policy, do not use (to remove in IDEA 14) */ |
| @SuppressWarnings("UnusedDeclaration") |
| public static List<String> loadLines(@NotNull Reader reader) throws IOException { |
| BufferedReader bufferedReader = new BufferedReader(reader); |
| try { |
| return loadLines(bufferedReader); |
| } |
| finally { |
| bufferedReader.close(); |
| } |
| } |
| |
| @NotNull |
| public static byte[] loadBytes(@NotNull InputStream stream) throws IOException { |
| return FileUtilRt.loadBytes(stream); |
| } |
| |
| @NotNull |
| public static byte[] loadBytes(@NotNull InputStream stream, int length) throws IOException { |
| return FileUtilRt.loadBytes(stream, length); |
| } |
| |
| @NotNull |
| public static List<String> splitPath(@NotNull String path) { |
| ArrayList<String> list = new ArrayList<String>(); |
| int index = 0; |
| int nextSeparator; |
| while ((nextSeparator = path.indexOf(File.separatorChar, index)) != -1) { |
| list.add(path.substring(index, nextSeparator)); |
| index = nextSeparator + 1; |
| } |
| list.add(path.substring(index, path.length())); |
| return list; |
| } |
| |
| @SuppressWarnings({"HardCodedStringLiteral"}) |
| public static boolean isJarOrZip(File file) { |
| if (file.isDirectory()) { |
| return false; |
| } |
| final String name = file.getName(); |
| return StringUtil.endsWithIgnoreCase(name, ".jar") || StringUtil.endsWithIgnoreCase(name, ".zip"); |
| } |
| |
| public static boolean visitFiles(@NotNull File root, @NotNull Processor<File> processor) { |
| if (!processor.process(root)) { |
| return false; |
| } |
| |
| File[] children = root.listFiles(); |
| if (children != null) { |
| for (File child : children) { |
| if (!visitFiles(child, processor)) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Like {@link Properties#load(java.io.Reader)}, but preserves the order of key/value pairs. |
| */ |
| @NotNull |
| public static Map<String, String> loadProperties(@NotNull Reader reader) throws IOException { |
| final Map<String, String> map = ContainerUtil.newLinkedHashMap(); |
| |
| new Properties() { |
| @Override |
| public synchronized Object put(Object key, Object value) { |
| map.put(String.valueOf(key), String.valueOf(value)); |
| //noinspection UseOfPropertiesAsHashtable |
| return super.put(key, value); |
| } |
| }.load(reader); |
| |
| return map; |
| } |
| |
| public static boolean isRootPath(@NotNull File file) { |
| return isRootPath(file.getPath()); |
| } |
| |
| public static boolean isRootPath(@NotNull String path) { |
| return path.equals("/") || path.matches("[a-zA-Z]:[/\\\\]"); |
| } |
| } |