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.IOException; 021import java.io.RandomAccessFile; 022import java.nio.channels.FileChannel; 023import java.util.Objects; 024 025import org.apache.commons.io.channels.FileChannels; 026 027/** 028 * Works with {@link RandomAccessFile}. 029 * 030 * @since 2.13.0 031 */ 032public class RandomAccessFiles { 033 034 /** 035 * Tests if two RandomAccessFile contents are equal. 036 * 037 * @param raf1 A RandomAccessFile. 038 * @param raf2 Another RandomAccessFile. 039 * @return true if the contents of both RandomAccessFiles are equal, false otherwise. 040 * @throws IOException if an I/O error occurs. 041 * @since 2.15.0 042 */ 043 @SuppressWarnings("resource") // See comments 044 public static boolean contentEquals(final RandomAccessFile raf1, final RandomAccessFile raf2) throws IOException { 045 // Short-circuit test 046 if (Objects.equals(raf1, raf2)) { 047 return true; 048 } 049 // Short-circuit test 050 final long length1 = length(raf1); 051 final long length2 = length(raf2); 052 if (length1 != length2) { 053 return false; 054 } 055 if (length1 == 0 && length2 == 0) { 056 return true; 057 } 058 // Dig in and to the work 059 // We do not close FileChannels because that closes the owning RandomAccessFile. 060 // Instead, the caller is assumed to manage the given RandomAccessFile objects. 061 final FileChannel channel1 = raf1.getChannel(); 062 final FileChannel channel2 = raf2.getChannel(); 063 return FileChannels.contentEquals(channel1, channel2, IOUtils.DEFAULT_BUFFER_SIZE); 064 } 065 066 private static long length(final RandomAccessFile raf) throws IOException { 067 return raf != null ? raf.length() : 0; 068 } 069 070 /** 071 * Reads a byte array starting at "position" for "length" bytes. 072 * 073 * @param input The source RandomAccessFile. 074 * @param position The offset position, measured in bytes from the beginning of the file, at which to set the file pointer. 075 * @param length How many bytes to read. 076 * @return a new byte array. 077 * @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 078 * other I/O error occurs. 079 */ 080 public static byte[] read(final RandomAccessFile input, final long position, final int length) throws IOException { 081 input.seek(position); 082 return IOUtils.toByteArray(input::read, length); 083 } 084 085 /** 086 * Resets the given file to position 0. 087 * 088 * @param raf The RandomAccessFile to reset. 089 * @return The given RandomAccessFile. 090 * @throws IOException If {@code pos} is less than {@code 0} or if an I/O error occurs. 091 * @since 2.15.0 092 */ 093 public static RandomAccessFile reset(final RandomAccessFile raf) throws IOException { 094 raf.seek(0); 095 return raf; 096 } 097 098 /** 099 * Make private in 3.0. 100 * 101 * @deprecated TODO Make private in 3.0. 102 */ 103 @Deprecated 104 public RandomAccessFiles() { 105 // empty 106 } 107}