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.IOException;
21 import java.io.RandomAccessFile;
22 import java.nio.channels.FileChannel;
23 import java.util.Objects;
24
25 import org.apache.commons.io.channels.FileChannels;
26
27 /**
28 * Works with {@link RandomAccessFile}.
29 *
30 * @since 2.13.0
31 */
32 public class RandomAccessFiles {
33
34 /**
35 * Tests if two RandomAccessFile contents are equal.
36 *
37 * @param raf1 A RandomAccessFile.
38 * @param raf2 Another RandomAccessFile.
39 * @return true if the contents of both RandomAccessFiles are equal, false otherwise.
40 * @throws IOException if an I/O error occurs.
41 * @since 2.15.0
42 */
43 @SuppressWarnings("resource") // See comments
44 public static boolean contentEquals(final RandomAccessFile raf1, final RandomAccessFile raf2) throws IOException {
45 // Short-circuit test
46 if (Objects.equals(raf1, raf2)) {
47 return true;
48 }
49 // Short-circuit test
50 final long length1 = length(raf1);
51 final long length2 = length(raf2);
52 if (length1 != length2) {
53 return false;
54 }
55 if (length1 == 0 && length2 == 0) {
56 return true;
57 }
58 // Dig in and to the work
59 // We do not close FileChannels because that closes the owning RandomAccessFile.
60 // Instead, the caller is assumed to manage the given RandomAccessFile objects.
61 final FileChannel channel1 = raf1.getChannel();
62 final FileChannel channel2 = raf2.getChannel();
63 return FileChannels.contentEquals(channel1, channel2, IOUtils.DEFAULT_BUFFER_SIZE);
64 }
65
66 private static long length(final RandomAccessFile raf) throws IOException {
67 return raf != null ? raf.length() : 0;
68 }
69
70 /**
71 * Reads a byte array starting at "position" for "length" bytes.
72 *
73 * @param input The source RandomAccessFile.
74 * @param position The offset position, measured in bytes from the beginning of the file, at which to set the file pointer.
75 * @param length How many bytes to read.
76 * @return a new byte array.
77 * @throws IOException If the first byte cannot be read for any reason other than end of file, or if the random access file has been closed, or if some
78 * other I/O error occurs.
79 */
80 public static byte[] read(final RandomAccessFile input, final long position, final int length) throws IOException {
81 input.seek(position);
82 return IOUtils.toByteArray(input::read, length);
83 }
84
85 /**
86 * Resets the given file to position 0.
87 *
88 * @param raf The RandomAccessFile to reset.
89 * @return The given RandomAccessFile.
90 * @throws IOException If {@code pos} is less than {@code 0} or if an I/O error occurs.
91 * @since 2.15.0
92 */
93 public static RandomAccessFile reset(final RandomAccessFile raf) throws IOException {
94 raf.seek(0);
95 return raf;
96 }
97
98 /**
99 * Make private in 3.0.
100 *
101 * @deprecated TODO Make private in 3.0.
102 */
103 @Deprecated
104 public RandomAccessFiles() {
105 // empty
106 }
107 }