1// Copyright 2016 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package com.google.archivepatcher.shared; 16 17import java.io.File; 18import java.io.IOException; 19import java.io.OutputStream; 20import java.io.RandomAccessFile; 21 22/** 23 * An {@link OutputStream} backed by a file that will be written serially. Allows pre-allocating 24 * the space for a stream as a file and then writing to that file as a stream. Call {@link #flush()} 25 * to force the data to be written to the backing storage. 26 */ 27public class RandomAccessFileOutputStream extends OutputStream { 28 /** 29 * The backing {@link RandomAccessFile}. 30 */ 31 private final RandomAccessFile raf; 32 33 /** 34 * Constructs a new instance that will immediately open the specified file for writing and set 35 * the length to the specified value. 36 * @param outputFile the file to wrap 37 * @param expectedSize if greater than or equal to zero, the size to set the file to immediately; 38 * otherwise, the file size is not set 39 * @throws IOException if unable to open the file for writing or set the size 40 */ 41 public RandomAccessFileOutputStream(File outputFile, long expectedSize) throws IOException { 42 this.raf = getRandomAccessFile(outputFile); 43 if (expectedSize >= 0) { 44 raf.setLength(expectedSize); 45 if (raf.length() != expectedSize) { 46 throw new IOException("Unable to set the file size"); 47 } 48 } 49 } 50 51 /** 52 * Given a {@link File}, get a writeable {@link RandomAccessFile} reference for it. 53 * @param file the file 54 * @return as described 55 * @throws IOException if unable to open the file 56 */ 57 protected RandomAccessFile getRandomAccessFile(File file) throws IOException { 58 return new RandomAccessFile(file, "rw"); 59 } 60 61 @Override 62 public void write(int b) throws IOException { 63 raf.write(b); 64 } 65 66 @Override 67 public void write(byte[] b) throws IOException { 68 write(b, 0, b.length); 69 } 70 71 @Override 72 public void write(byte[] b, int off, int len) throws IOException { 73 raf.write(b, off, len); 74 } 75 76 @Override 77 public void flush() throws IOException { 78 raf.getChannel().force(true); 79 } 80 81 @Override 82 public void close() throws IOException { 83 flush(); 84 raf.close(); 85 } 86} 87