Removed desktop path detection. Was too ugly and unreliable.
[svjatoslav_commons.git] / src / main / java / eu / svjatoslav / commons / file / IOHelper.java
1 /*
2  * Svjatoslav Commons - shared library of common functionality. Author: Svjatoslav Agejenko.
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.commons.file;
6
7 import java.io.*;
8
9 import static java.nio.charset.StandardCharsets.UTF_8;
10 import static java.nio.file.Files.isSymbolicLink;
11
12 public class IOHelper {
13
14     /**
15      * Deletes files and directories recursively. Does not follow symlinks.
16      *
17      * @param file directory to delete with entire contents.
18      * @throws IOException if filesystem error happens
19      */
20     public static void deleteRecursively(final File file) throws IOException {
21
22         if (file.isDirectory()) {
23             deleteDirectory(file);
24             return;
25         }
26
27         if (file.isFile()){
28             if (!file.delete()) throw new IOException("Failed to delete file: " + file);
29         } else {
30             if (isSymbolicLink(file.toPath()) && !file.delete())
31                 throw new IOException("Failed to delete symlink: " + file);
32         }
33     }
34
35     private static void deleteDirectory(File file) throws IOException {
36         // if file is symlink that points to directory, no not touch content
37         if (!isSymbolicLink(file.toPath())){
38             File[] files = file.listFiles();
39             if (files == null)
40                 throw new IOException("Failed to read directory content for: "
41                         + file);
42
43             for (final File subFile : files)
44                 deleteRecursively(subFile);
45         }
46
47         if (!file.delete())
48             throw new IOException("Failed to delete directory: " + file);
49     }
50
51     public static byte[] getFileContents(final File file)
52             throws IOException {
53
54         final byte[] result = new byte[(int) file.length()];
55         try (final FileInputStream fileInputStream = new FileInputStream(file)) {
56             if (fileInputStream.read(result) != result.length)
57                 throw new RuntimeException("Could not read file content:" + file);
58         }
59         return result;
60     }
61
62     /**
63      * Expects file content to be in UTF-8 encoding.
64      * @param file file to read
65      * @return File content
66      * @throws IOException when file reading fails.
67      */
68     public static String getFileContentsAsString(final File file)
69             throws IOException {
70         try {
71             return new String(getFileContents(file), UTF_8);
72         } catch (final UnsupportedEncodingException exception) {
73             throw new RuntimeException(exception);
74         }
75     }
76
77     /**
78      * Compares new file content with old file content. If content in equal,
79      * then leaves file as-is. If content differs, then overrides file with the
80      * new content.
81      *
82      * @param file       file to potentially overwrite
83      * @param newContent new content
84      * @return <code>true</code> if file was overwritten.
85      * @throws FileNotFoundException if file is not found.
86      * @throws IOException           if error happens during file IO.
87      */
88     public static boolean overwriteFileIfContentDiffers(final File file,
89                                                         final byte[] newContent) throws IOException {
90
91         checkForEquality:
92         {
93             if (file.length() == newContent.length) {
94
95                 final byte[] oldContent = getFileContents(file);
96
97                 for (int i = 0; i < newContent.length; i++)
98                     if (newContent[i] != oldContent[i])
99                         break checkForEquality;
100
101                 // new file content in identical to old content
102                 return false;
103             }
104         }
105
106         // New content differs from existing. Overwrite file.
107         saveToFile(file, newContent);
108         return true;
109     }
110
111     public static void saveToFile(final File file, final byte[] content)
112             throws IOException {
113         try (final FileOutputStream fos = new FileOutputStream(file)) {
114             fos.write(content);
115         }
116     }
117
118     public static void saveToFile(final File file, final String content)
119             throws IOException {
120         saveToFile(file, content.getBytes(UTF_8));
121     }
122
123 }