All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.ratis.util.FileUtils Maven / Gradle / Ivy

There is a newer version: 3.1.2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.ratis.util; import org.apache.ratis.util.function.CheckedSupplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.function.Supplier; public interface FileUtils { Logger LOG = LoggerFactory.getLogger(FileUtils.class); int NUM_ATTEMPTS = 5; TimeDuration SLEEP_TIME = TimeDuration.ONE_SECOND; static T attempt(CheckedSupplier op, Supplier name) throws IOException { try { return JavaUtils.attempt(op, NUM_ATTEMPTS, SLEEP_TIME, name, LOG); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw IOUtils.toInterruptedIOException("Interrupted " + name.get(), e); } } static void truncateFile(File f, long target) throws IOException { final long original = f.length(); LogUtils.runAndLog(LOG, () -> { try (FileChannel channel = FileChannel.open(f.toPath(), StandardOpenOption.WRITE)) { channel.truncate(target); } }, () -> "FileChannel.truncate " + f + " length: " + original + " -> " + target); } static InputStream newInputStream(String s, OpenOption... options) throws IOException { return newInputStream(Paths.get(s), options); } static InputStream newInputStream(File f, OpenOption... options) throws IOException { return newInputStream(f.toPath(), options); } static InputStream newInputStream(Path p, OpenOption... options) throws IOException { return LogUtils.supplyAndLog(LOG, () -> Files.newInputStream(p, options), () -> "Files.newInputStream " + p + " with options " + Arrays.asList(options)); } static OutputStream newOutputStream(File f, OpenOption... options) throws IOException { return newOutputStream(f.toPath(), options); } static OutputStream newOutputStream(Path p, OpenOption... options) throws IOException { return LogUtils.supplyAndLog(LOG, () -> Files.newOutputStream(p, options), () -> "Files.newOutputStream " + p + " with options " + Arrays.asList(options)); } static OutputStream newOutputStream(FileChannel channel, boolean forceAtClose) { final byte[] single = {0}; return new OutputStream() { @Override public void write(int b) throws IOException { single[0] = (byte) b; write(single); } @Override public void write(byte[] b, int off, int len) throws IOException { for(; len > 0; ) { final int written = channel.write(ByteBuffer.wrap(b, off, len)); off += written; len -= written; } } @Override public void close() throws IOException { try (FileChannel c = channel) { if (forceAtClose) { c.force(true); } } } }; } static OutputStream newOutputStreamForceAtClose(Path p, OpenOption... options) throws IOException { return newOutputStream(newFileChannel(p, options), true); } static OutputStream newOutputStreamForceAtClose(File f, OpenOption... options) throws IOException { return newOutputStreamForceAtClose(f.toPath(), options); } static FileChannel newFileChannel(File f, OpenOption... options) throws IOException { return newFileChannel(f.toPath(), options); } static FileChannel newFileChannel(Path p, OpenOption... options) throws IOException { return LogUtils.supplyAndLog(LOG, () -> FileChannel.open(p, options), () -> "FileChannel.open " + p + " with options " + Arrays.asList(options)); } static void createDirectories(File dir) throws IOException { createDirectories(dir.toPath()); } static void createDirectories(Path dir) throws IOException { LogUtils.runAndLog(LOG, () -> Files.createDirectories(dir), () -> "Files.createDirectories " + dir); } static void createDirectoriesDeleteExistingNonDirectory(File dir) throws IOException { createDirectoriesDeleteExistingNonDirectory(dir.toPath()); } static void createDirectoriesDeleteExistingNonDirectory(Path dir) throws IOException { try { createDirectories(dir); } catch (FileAlreadyExistsException e) { LOG.warn("Failed to create directory " + dir + " since it already exists as a non-directory. Trying to delete it ...", e); delete(dir); createDirectories(dir); } } static void move(File src, File dst, CopyOption... options) throws IOException { move(src.toPath(), dst.toPath(), options); } static void move(Path src, Path dst, CopyOption... options) throws IOException { Objects.requireNonNull(options, "options == null"); final List original = Arrays.asList(options); final boolean atomicMove = original.contains(StandardCopyOption.ATOMIC_MOVE); if (atomicMove) { LogUtils.runAndLog(LOG, () -> Files.move(src, dst, options), () -> "Files.move " + src + " to " + dst + " with options " + original); return; } final CopyOption[] optionsWithAtomicMove = new CopyOption[options.length + 1]; optionsWithAtomicMove[0] = StandardCopyOption.ATOMIC_MOVE; System.arraycopy(options, 0, optionsWithAtomicMove, 1, options.length); final Supplier suffix = () -> original.isEmpty() ? "" : " with options " + original; try { LogUtils.runAndLog(LOG, () -> Files.move(src, dst, optionsWithAtomicMove), () -> "Atomic Files.move " + src + " to " + dst + suffix.get()); } catch (AtomicMoveNotSupportedException e) { // Fallback to non-atomic move. LogUtils.runAndLog(LOG, () -> Files.move(src, dst, options), () -> "Atomic move not supported. Fallback to Files.move " + src + " to " + dst + suffix.get()); } } /** * Move src to a new path, * where the new path created by appending the given suffix to the src. * * @return the new file if rename succeeded; otherwise, return null. */ static File move(File src, String suffix) throws IOException { final File newFile = new File(src.getPath() + suffix); move(src, newFile); return newFile; } /** The same as passing f.toPath() to {@link #delete(Path)}. */ static void deleteFile(File f) throws IOException { delete(f.toPath()); } /** * Moves the directory. If any file is locked, the exception is caught * and logged and continues to other files. * @param source * @param dest * @throws IOException */ static void moveDirectory(Path source, Path dest) throws IOException { if (LOG.isTraceEnabled()) { LOG.trace("moveDirectory source: {} dest: {}", source, dest); } createDirectories(dest); Files.walkFileTree(source, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { Path targetPath = dest.resolve(source.relativize(dir)); if (!Files.exists(targetPath)) { createDirectories(targetPath); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { try { move(file, dest.resolve(source.relativize(file))); } catch (IOException e) { LOG.info("Files.moveDirectory: could not delete {}", file.getFileName()); } return FileVisitResult.CONTINUE; } }); /* Delete the source since all the files has been moved. */ deleteFully(source); } /** * The same as passing f.toPath() to {@link #deletePathQuietly(Path)}. * * @param f file to delete * @return true if the file is successfully deleted false otherwise */ static boolean deleteFileQuietly(File f) { return deletePathQuietly(f.toPath()); } /** * Delete the given path quietly. * Only print a debug message in case that there is an exception, * * @param p path to delete * @return true if the path is successfully deleted false otherwise */ static boolean deletePathQuietly(Path p) { try { delete(p); return true; } catch (Exception ex) { LOG.debug("Failed to delete " + p.toAbsolutePath(), ex); return false; } } /** * Use {@link Files#delete(Path)} to delete the given path. * * This method may print log messages using {@link #LOG}. */ static void delete(Path p) throws IOException { LogUtils.runAndLog(LOG, () -> Files.delete(p), () -> "Files.delete " + p); } /** * Use {@link Files#deleteIfExists(Path)} to delete the given path. * This method may print log messages using {@link #LOG}. */ static void deleteIfExists(Path p) throws IOException { LogUtils.runAndLog(LOG, () -> Files.deleteIfExists(p), () -> "Files.deleteIfExists " + p); } /** * Use {@link Files#deleteIfExists(Path)} to delete the given path. * This method may print log messages using {@link #LOG}. */ static void deleteIfExists(File f) throws IOException { deleteIfExists(f.toPath()); } /** The same as passing f.toPath() to {@link #deleteFully(Path)}. */ static void deleteFully(File f) throws IOException { LOG.trace("deleteFully {}", f); deleteFully(f.toPath()); } /** * Delete fully the given path. * (1) If it is a file, the file will be deleted. * (2) If it is a directory, the directory and all its contents will be recursively deleted. * If an exception is thrown, the directory may possibly be partially deleted.* * (3) If it is a symlink, the symlink will be deleted but the symlink target will not be deleted. */ static void deleteFully(Path p) throws IOException { if (!Files.exists(p, LinkOption.NOFOLLOW_LINKS)) { LOG.trace("deleteFully: {} does not exist.", p); return; } Files.walkFileTree(p, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException { if (e != null) { // directory iteration failed throw e; } delete(dir); return FileVisitResult.CONTINUE; } }); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy