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.output; 019 020import java.io.File; 021import java.io.IOException; 022import java.io.OutputStream; 023import java.io.RandomAccessFile; 024import java.nio.file.StandardOpenOption; 025 026import org.apache.commons.io.build.AbstractOrigin; 027import org.apache.commons.io.build.AbstractStreamBuilder; 028 029/** 030 * An {@link OutputStream} that writes to a {@link RandomAccessFile}. 031 * 032 * @since 2.18.0 033 */ 034public final class RandomAccessFileOutputStream extends OutputStream { 035 036 // @formatter:off 037 /** 038 * Builds a new {@link RandomAccessFileOutputStream}. 039 * <p> 040 * For example: 041 * </p> 042 * <pre>{@code 043 * RandomAccessFileOutputStream s = RandomAccessFileOutputStream.builder() 044 * .setFile("myfile.txt") 045 * .setOpenOptions(StandardOpenOption.SYNC) 046 * .get();} 047 * </pre> 048 * <p> 049 * The only super's aspect used is buffer size. 050 * </p> 051 * 052 * @see #get() 053 */ 054 // @formatter:on 055 public static final class Builder extends AbstractStreamBuilder<RandomAccessFileOutputStream, Builder> { 056 057 /** 058 * Use {@link RandomAccessFileOutputStream#builder()}. 059 */ 060 private Builder() { 061 setOpenOptions(StandardOpenOption.WRITE); 062 } 063 064 /** 065 * Builds a new {@link RandomAccessFileOutputStream}. 066 * <p> 067 * You must set an aspect that supports {@link RandomAccessFile} or {@link File}, otherwise, this method throws an exception. Only set one of 068 * RandomAccessFile or an origin that can be converted to a File. 069 * </p> 070 * <p> 071 * This builder uses the following aspects: 072 * </p> 073 * <ul> 074 * <li>{@link RandomAccessFile} is the target aspect.</li> 075 * <li>{@link File}</li> 076 * <li>closeOnClose</li> 077 * </ul> 078 * 079 * @return a new instance. 080 * @throws IllegalStateException if the {@code origin} is {@code null}. 081 * @throws IllegalStateException if both RandomAccessFile and origin are set. 082 * @throws UnsupportedOperationException if the origin cannot be converted to a {@link RandomAccessFile}. 083 * @throws IOException if an I/O error occurs converting to an {@link RandomAccessFile} using {@link #getRandomAccessFile()}. 084 * @see AbstractOrigin#getFile() 085 * @see #getUnchecked() 086 */ 087 @Override 088 public RandomAccessFileOutputStream get() throws IOException { 089 return new RandomAccessFileOutputStream(this); 090 } 091 092 } 093 094 /** 095 * Constructs a new {@link Builder}. 096 * 097 * @return a new {@link Builder}. 098 */ 099 public static Builder builder() { 100 return new Builder(); 101 } 102 103 private final RandomAccessFile randomAccessFile; 104 105 private RandomAccessFileOutputStream(final Builder builder) throws IOException { 106 this.randomAccessFile = builder.getRandomAccessFile(); 107 } 108 109 @Override 110 public void close() throws IOException { 111 this.randomAccessFile.close(); 112 super.close(); 113 } 114 115 @SuppressWarnings("resource") 116 @Override 117 public void flush() throws IOException { 118 randomAccessFile.getChannel().force(true); 119 super.flush(); 120 } 121 122 /** 123 * Gets the underlying random access file. 124 * 125 * @return the underlying random access file. 126 * @since 2.19.0 127 */ 128 public RandomAccessFile getRandomAccessFile() { 129 return randomAccessFile; 130 } 131 132 @Override 133 public void write(final int b) throws IOException { 134 randomAccessFile.write(b); 135 } 136 137}