View Javadoc
1   /**************************************************************************
2    *
3    * Copyright (c) 2016-2020 Yawg project contributors.
4    *
5    **************************************************************************/
6   
7   package com.varmateo.yawg.util;
8   
9   import java.io.IOException;
10  import java.io.Reader;
11  import java.io.Writer;
12  import java.nio.charset.StandardCharsets;
13  import java.nio.file.Files;
14  import java.nio.file.Path;
15  import java.nio.file.StandardCopyOption;
16  import java.util.Optional;
17  import java.util.regex.Pattern;
18  
19  import io.vavr.control.Option;
20  import io.vavr.control.Try;
21  
22  
23  /**
24   * Utility functions for managing files and directories.
25   */
26  public final class FileUtils {
27  
28  
29      /**
30       * No instances of this class are to be created.
31       */
32      private FileUtils() {
33          // Nothing to do.
34      }
35  
36  
37      /**
38       * Determines the basename of the given file.
39       *
40       * <p>The basename is the name of the file without extension.</p>
41       *
42       * @param path The path of the file for which the basename will be
43       * determined.
44       *
45       * @return The basename of the given file.
46       */
47      public static String basename(final Path path) {
48  
49          final String basenameWithExtension =
50                  Option.of(path.getFileName())
51                  .map(Object::toString)
52                  .getOrElse("");
53          final int extensionIndex = basenameWithExtension.lastIndexOf('.');
54  
55          return (extensionIndex > -1)
56                  ? basenameWithExtension.substring(0, extensionIndex)
57                  : basenameWithExtension;
58      }
59  
60  
61      /**
62       *
63       */
64      public static boolean isNameMatch(
65              final Path path,
66              final Pattern pattern) {
67  
68          return  Optional.ofNullable(path.getFileName())
69                  .map(Path::toString)
70                  .map(basename -> pattern.matcher(basename).matches())
71                  .orElse(false);
72      }
73  
74  
75      /**
76       * Copies one file to a given location.
77       *
78       * <p>If the target file already exists, itl will be overwritten</p>
79       *
80       * @param source The path of the source file to be copied.
81       *
82       * @param target The path of the target file to be created. Its
83       * parent directory is supposed to exist.
84       *
85       * @throws IOException If there were problems reading from the
86       * source file, or writing to the target file.
87       */
88      public static void copy(
89              final Path source,
90              final Path target)
91              throws IOException {
92  
93          Files.copy(
94                  source,
95                  target,
96                  StandardCopyOption.REPLACE_EXISTING,
97                  StandardCopyOption.COPY_ATTRIBUTES);
98      }
99  
100 
101     /**
102      *
103      */
104     public static Try<Void> safeCopy(
105             final Path source,
106             final Path target) {
107 
108         return Try.run(() -> copy(source, target));
109     }
110 
111 
112     /**
113      * Reads the contents of a file into a string.
114      *
115      * <p>The file is expected to be UTF-8 encoded.</p>
116      *
117      * @param sourcePath The file to be read.
118      *
119      * @return The contents of the given file as a string.
120      *
121      * @throws IOException if there were any problems reading the
122      * file.
123      */
124     public static String readAsString(final Path sourcePath)
125             throws IOException {
126 
127         final byte[] contentBytes = Files.readAllBytes(sourcePath);
128 
129         return new String(contentBytes, StandardCharsets.UTF_8);
130     }
131 
132 
133     /**
134      * Creates a new <code>Writer</code> and passes it to the given
135      * consumer.
136      *
137      * <p>The <code>Writer</code> passed to the consumer is a buffered
138      * writer with UTF-8 pointing to the given target file. The
139      * <code>Writer</code> is ensured to be closed when this method
140      * returns.</p>
141      *
142      * @param target The file to be written.
143      *
144      * @param consumer The consumer that is suppoed to write into the
145      * <code>Writer</code> associated with the given target file.
146      *
147      * @throws IOException If there were problems opening the file for
148      * writing, or writing into the file.
149      */
150     public static void writeTo(
151             final Path target,
152             final ConsumerWithIoException<Writer> consumer)
153             throws IOException {
154 
155         try ( Writer writer = Files.newBufferedWriter(target, StandardCharsets.UTF_8) ) {
156             consumer.accept(writer);
157         }
158     }
159 
160 
161     /**
162      *
163      */
164     public static <T> Try<Void> safeWriteTo(
165             final Path target,
166             final ConsumerWithIoException<Writer> action) {
167 
168         try ( Writer writer = Files.newBufferedWriter(target, StandardCharsets.UTF_8) ) {
169             return Try.run(() -> action.accept(writer));
170         } catch ( final IOException cause ) {
171             return Try.failure(cause);
172         }
173     }
174 
175 
176     /**
177      *
178      */
179     public static <T> Try<T> safeWriteWith(
180             final Path target,
181             final FunctionWithIoException<Writer, T> action) {
182 
183         try ( Writer writer = Files.newBufferedWriter(target, StandardCharsets.UTF_8) ) {
184             return Try.of(() -> action.apply(writer));
185         } catch ( final IOException cause ) {
186             return Try.failure(cause);
187         }
188     }
189 
190 
191     /**
192      *
193      */
194     public static <T> T readFrom(
195             final Path source,
196             final FunctionWithIoException<Reader, T> transformer)
197             throws IOException {
198 
199         try ( Reader reader = Files.newBufferedReader(source, StandardCharsets.UTF_8) ) {
200             return transformer.apply(reader);
201         }
202     }
203 
204 
205     /**
206      *
207      */
208     public static <T> Try<T> safeReadFrom(
209             final Path source,
210             final FunctionWithIoException<Reader, T> transformer) {
211 
212         final Try<T> result;
213 
214         try ( Reader reader = Files.newBufferedReader(source, StandardCharsets.UTF_8) ) {
215             return Try.of(() -> transformer.apply(reader));
216         } catch ( final IOException cause ) {
217             return Try.failure(cause);
218         }
219     }
220 
221 
222     /**
223      * Similar to a <code>java.util.function.Consumer</code> but
224      * throws <code>IOException</code>. Intended for simplifying the
225      * use of lambdas when calling the <code>newWriter(...)</code>
226      * method.
227      *
228      * @param <T> The input type for the consumer.
229      */
230     @FunctionalInterface
231     public interface ConsumerWithIoException<T> {
232 
233         /**
234          * Performs the operation on the given argument.
235          *
236          * @param input The input object.
237          *
238          * @throws IOException For whatever reason.
239          */
240         void accept(T input)
241                 throws IOException;
242     }
243 
244 
245     /**
246      *
247      */
248     @FunctionalInterface
249     public interface SupplierWithIoException<T> {
250 
251         /**
252          *
253          */
254         T get()
255                 throws IOException;
256     }
257 
258 
259     /**
260      *
261      */
262     @FunctionalInterface
263     public interface FunctionWithIoException<T, R> {
264 
265         /**
266          *
267          */
268         R apply(T input)
269                 throws IOException;
270     }
271 
272 
273 }