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.SeekableByteChannel;
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 would close the owning RandomAccessFile.
60 // Instead, the caller is assumed to manage the given RandomAccessFile objects.
61 return FileChannels.contentEquals((SeekableByteChannel) raf1.getChannel(), raf2.getChannel(), IOUtils.DEFAULT_BUFFER_SIZE);
62 }
63
64 private static long length(final RandomAccessFile raf) throws IOException {
65 return raf != null ? raf.length() : 0;
66 }
67
68 /**
69 * Reads a byte array starting at "position" for "length" bytes.
70 *
71 * @param input The source RandomAccessFile.
72 * @param position The offset position, measured in bytes from the beginning of the file, at which to set the file pointer.
73 * @param length How many bytes to read.
74 * @return a new byte array.
75 * @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
76 * other I/O error occurs.
77 */
78 public static byte[] read(final RandomAccessFile input, final long position, final int length) throws IOException {
79 input.seek(position);
80 return IOUtils.toByteArray(input::read, length);
81 }
82
83 /**
84 * Resets the given file to position 0.
85 *
86 * @param raf The RandomAccessFile to reset.
87 * @return The given RandomAccessFile.
88 * @throws IOException If {@code pos} is less than {@code 0} or if an I/O error occurs.
89 * @since 2.15.0
90 */
91 public static RandomAccessFile reset(final RandomAccessFile raf) throws IOException {
92 raf.seek(0);
93 return raf;
94 }
95
96 /**
97 * Make private in 3.0.
98 *
99 * @deprecated TODO Make private in 3.0.
100 */
101 @Deprecated
102 public RandomAccessFiles() {
103 // empty
104 }
105 }