1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.io; 19 20 import java.io.File; 21 import java.io.FileNotFoundException; 22 import java.io.IOException; 23 import java.io.RandomAccessFile; 24 import java.nio.file.OpenOption; 25 import java.nio.file.Path; 26 import java.nio.file.StandardOpenOption; 27 import java.util.Objects; 28 29 import org.apache.commons.io.function.IOConsumer; 30 import org.apache.commons.io.function.IOFunction; 31 32 /** 33 * Enumerates access modes for {@link RandomAccessFile} with factory methods. 34 * 35 * @see RandomAccessFile#RandomAccessFile(File, String) 36 * @see RandomAccessFile#RandomAccessFile(String, String) 37 * @see Enum 38 * @since 2.12.0 39 */ 40 public enum RandomAccessFileMode { 41 42 /** 43 * Defines mode {@value #R} to open a {@link RandomAccessFile} for reading only. 44 * 45 * @see RandomAccessFile#RandomAccessFile(File, String) 46 * @see RandomAccessFile#RandomAccessFile(String, String) 47 */ 48 READ_ONLY(RandomAccessFileMode.R, 1), // NOPMD bug https://github.com/pmd/pmd/issues/5263 49 50 /** 51 * Defines mode {@value #RW} to open a {@link RandomAccessFile} for reading and writing. 52 * 53 * @see RandomAccessFile#RandomAccessFile(File, String) 54 * @see RandomAccessFile#RandomAccessFile(String, String) 55 */ 56 READ_WRITE(RandomAccessFileMode.RW, 2), // NOPMD bug https://github.com/pmd/pmd/issues/5263 57 58 /** 59 * Defines mode {@value #RWS} to open a {@link RandomAccessFile} for reading and writing, as with {@value #RW}, and also require that every update to the 60 * file's content or metadata be written synchronously to the underlying storage device. 61 * 62 * @see RandomAccessFile#RandomAccessFile(File, String) 63 * @see RandomAccessFile#RandomAccessFile(String, String) 64 * @see StandardOpenOption#SYNC 65 */ 66 READ_WRITE_SYNC_ALL(RandomAccessFileMode.RWS, 4), // NOPMD bug https://github.com/pmd/pmd/issues/5263 67 68 /** 69 * Defines mode {@value #RWD} to open a {@link RandomAccessFile} for reading and writing, as with {@value #RW}, and also require that every update to the 70 * file's content be written synchronously to the underlying storage device. 71 * 72 * @see RandomAccessFile#RandomAccessFile(File, String) 73 * @see RandomAccessFile#RandomAccessFile(String, String) 74 * @see StandardOpenOption#DSYNC 75 */ 76 READ_WRITE_SYNC_CONTENT(RandomAccessFileMode.RWD, 3); // NOPMD bug https://github.com/pmd/pmd/issues/5263 77 78 private static final String R = "r"; 79 private static final String RW = "rw"; 80 private static final String RWD = "rwd"; 81 private static final String RWS = "rws"; 82 83 /** 84 * Gets the enum value that best fits the given {@link OpenOption}s. 85 * <p> 86 * The input must be a legal and working combination for NIO. 87 * </p> 88 * 89 * @param openOption options like {@link StandardOpenOption}. 90 * @return best fit, by default {@link #READ_ONLY}. 91 * @see StandardOpenOption 92 * @since 2.18.0 93 */ 94 public static RandomAccessFileMode valueOf(final OpenOption... openOption) { 95 RandomAccessFileMode bestFit = READ_ONLY; 96 for (final OpenOption option : openOption) { 97 if (option instanceof StandardOpenOption) { 98 switch ((StandardOpenOption) option) { 99 case WRITE: 100 if (!bestFit.implies(READ_WRITE)) { 101 bestFit = READ_WRITE; 102 } 103 break; 104 case DSYNC: 105 if (!bestFit.implies(READ_WRITE_SYNC_CONTENT)) { 106 bestFit = READ_WRITE_SYNC_CONTENT; 107 } 108 break; 109 case SYNC: 110 if (!bestFit.implies(READ_WRITE_SYNC_ALL)) { 111 bestFit = READ_WRITE_SYNC_ALL; 112 } 113 break; 114 default: 115 // explicit case skip (spotbugs) 116 continue; 117 } 118 } 119 } 120 return bestFit; 121 } 122 123 /** 124 * Gets the {@link RandomAccessFileMode} value for the given mode, one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}. 125 * 126 * @param mode one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}. 127 * @return A RandomAccessFileMode. 128 * @throws IllegalArgumentException Thrown when mode is not one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}. 129 * @since 2.18.0 130 */ 131 public static RandomAccessFileMode valueOfMode(final String mode) { 132 switch (mode) { 133 case R: 134 return READ_ONLY; 135 case RW: 136 return READ_WRITE; 137 case RWD: 138 return READ_WRITE_SYNC_CONTENT; 139 case RWS: 140 return READ_WRITE_SYNC_ALL; 141 } 142 throw new IllegalArgumentException(mode); 143 } 144 145 private final int level; 146 147 private final String mode; 148 149 RandomAccessFileMode(final String mode, final int level) { 150 this.mode = mode; 151 this.level = level; 152 } 153 154 /** 155 * Performs an operation on the {@link RandomAccessFile} specified at the given {@link Path}. 156 * <p> 157 * This method allocates and releases the {@link RandomAccessFile} given to the consumer. 158 * </p> 159 * 160 * @param file the file specifying the {@link RandomAccessFile} to open. 161 * @param consumer the function to apply. 162 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}. 163 * @throws IOException Thrown by the given function. 164 * @since 2.18.0 165 */ 166 public void accept(final Path file, final IOConsumer<RandomAccessFile> consumer) throws IOException { 167 try (RandomAccessFile raf = create(file)) { 168 consumer.accept(raf); 169 } 170 } 171 172 /** 173 * Applies the given function for a {@link RandomAccessFile} specified at the given {@link Path}. 174 * <p> 175 * This method allocates and releases the {@link RandomAccessFile} given to the function. 176 * </p> 177 * 178 * @param <T> the return type of the function. 179 * @param file the file specifying the {@link RandomAccessFile} to open. 180 * @param function the function to apply. 181 * @return the function's result value. 182 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}. 183 * @throws IOException Thrown by the given function. 184 * @since 2.18.0 185 */ 186 public <T> T apply(final Path file, final IOFunction<RandomAccessFile, T> function) throws IOException { 187 try (RandomAccessFile raf = create(file)) { 188 return function.apply(raf); 189 } 190 } 191 192 /** 193 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument. 194 * <p> 195 * Prefer {@link #create(Path)} over this. 196 * </p> 197 * 198 * @param file the file object 199 * @return a random access file 200 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}. 201 */ 202 public RandomAccessFile create(final File file) throws FileNotFoundException { 203 return new IORandomAccessFile(file, mode); 204 } 205 206 /** 207 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument. 208 * 209 * @param file the file object 210 * @return a random access file 211 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}. 212 */ 213 public RandomAccessFile create(final Path file) throws FileNotFoundException { 214 return create(Objects.requireNonNull(file.toFile(), "file")); 215 } 216 217 /** 218 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument. 219 * <p> 220 * Prefer {@link #create(Path)} over this. 221 * </p> 222 * 223 * @param name the file object 224 * @return a random access file 225 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}. 226 */ 227 public RandomAccessFile create(final String name) throws FileNotFoundException { 228 return new IORandomAccessFile(name, mode); 229 } 230 231 /** 232 * A level for relative comparison of access mode rights, the larger, the more access. 233 * <p> 234 * The relative order from lowest to highest access rights is: 235 * </p> 236 * <ol> 237 * <li>{@link #READ_ONLY}</li> 238 * <li>{@link #READ_WRITE}</li> 239 * <li>{@link #READ_WRITE_SYNC_CONTENT}</li> 240 * <li>{@link #READ_WRITE_SYNC_ALL}</li> 241 * </ol> 242 * <p> 243 * This is unrelated to {@link #ordinal()}. 244 * </p> 245 * 246 * @return A level for relative comparison. 247 */ 248 private int getLevel() { 249 return level; 250 } 251 252 /** 253 * Gets the access mode, one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}. 254 * 255 * @return one of {@value #R}, {@value #RW}, {@value #RWD}, or {@value #RWS}. 256 * @since 2.18.0 257 */ 258 public String getMode() { 259 return mode; 260 } 261 262 /** 263 * Tests whether this mode implies the given {@code other} mode. 264 * <p> 265 * For example: 266 * </p> 267 * <ol> 268 * <li>{@link RandomAccessFileMode#READ_WRITE_SYNC_ALL} implies {{@link RandomAccessFileMode#READ_WRITE_SYNC_CONTENT}}.</li> 269 * <li>{@link RandomAccessFileMode#READ_WRITE_SYNC_CONTENT} implies {{@link RandomAccessFileMode#READ_WRITE}}.</li> 270 * <li>{@link RandomAccessFileMode#READ_WRITE} implies {{@link RandomAccessFileMode#READ_ONLY}}.</li> 271 * </ol> 272 * 273 * @param other the non-null mode to test against. 274 * @return whether this mode implies the given {@code other} mode. 275 * @since 2.18.0 276 */ 277 public boolean implies(final RandomAccessFileMode other) { 278 // Note: The method name "implies" is inspired by java.security.Permission.implies(Permission) 279 return getLevel() >= other.getLevel(); 280 } 281 282 /** 283 * Constructs a random access file to read from, and optionally to write to, the file specified by the {@link File} argument. 284 * 285 * @param name the file object 286 * @return a random access file 287 * @throws FileNotFoundException See {@link IORandomAccessFile#IORandomAccessFile(File, String)}. 288 * @since 2.18.0 289 */ 290 public IORandomAccessFile io(final String name) throws FileNotFoundException { 291 return new IORandomAccessFile(name, mode); 292 } 293 294 }