001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.io; 019 020import java.io.File; 021import java.io.FileNotFoundException; 022import java.io.IOException; 023import java.io.RandomAccessFile; 024import java.nio.file.OpenOption; 025import java.nio.file.Path; 026import java.nio.file.StandardOpenOption; 027import java.util.Objects; 028 029import org.apache.commons.io.function.IOConsumer; 030import org.apache.commons.io.function.IOFunction; 031 032/** 033 * Enumerates access modes for {@link RandomAccessFile} with factory methods. 034 * 035 * @see RandomAccessFile#RandomAccessFile(File, String) 036 * @see RandomAccessFile#RandomAccessFile(String, String) 037 * @see Enum 038 * @since 2.12.0 039 */ 040public enum RandomAccessFileMode { 041 042 /** 043 * Defines mode {@value #R} to open a {@link RandomAccessFile} for reading only. 044 * 045 * @see RandomAccessFile#RandomAccessFile(File, String) 046 * @see RandomAccessFile#RandomAccessFile(String, String) 047 */ 048 READ_ONLY(RandomAccessFileMode.R, 1), // NOPMD bug https://github.com/pmd/pmd/issues/5263 049 050 /** 051 * Defines mode {@value #RW} to open a {@link RandomAccessFile} for reading and writing. 052 * 053 * @see RandomAccessFile#RandomAccessFile(File, String) 054 * @see RandomAccessFile#RandomAccessFile(String, String) 055 */ 056 READ_WRITE(RandomAccessFileMode.RW, 2), // NOPMD bug https://github.com/pmd/pmd/issues/5263 057 058 /** 059 * 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 060 * file's content or metadata be written synchronously to the underlying storage device. 061 * 062 * @see RandomAccessFile#RandomAccessFile(File, String) 063 * @see RandomAccessFile#RandomAccessFile(String, String) 064 * @see StandardOpenOption#SYNC 065 */ 066 READ_WRITE_SYNC_ALL(RandomAccessFileMode.RWS, 4), // NOPMD bug https://github.com/pmd/pmd/issues/5263 067 068 /** 069 * 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 070 * file's content be written synchronously to the underlying storage device. 071 * 072 * @see RandomAccessFile#RandomAccessFile(File, String) 073 * @see RandomAccessFile#RandomAccessFile(String, String) 074 * @see StandardOpenOption#DSYNC 075 */ 076 READ_WRITE_SYNC_CONTENT(RandomAccessFileMode.RWD, 3); // NOPMD bug https://github.com/pmd/pmd/issues/5263 077 078 private static final String R = "r"; 079 private static final String RW = "rw"; 080 private static final String RWD = "rwd"; 081 private static final String RWS = "rws"; 082 083 /** 084 * Gets the enum value that best fits the given {@link OpenOption}s. 085 * <p> 086 * The input must be a legal and working combination for NIO. 087 * </p> 088 * 089 * @param openOption options like {@link StandardOpenOption}. 090 * @return best fit, by default {@link #READ_ONLY}. 091 * @see StandardOpenOption 092 * @since 2.18.0 093 */ 094 public static RandomAccessFileMode valueOf(final OpenOption... openOption) { 095 RandomAccessFileMode bestFit = READ_ONLY; 096 for (final OpenOption option : openOption) { 097 if (option instanceof StandardOpenOption) { 098 switch ((StandardOpenOption) option) { 099 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}