View Javadoc
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.output;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.OutputStream;
23  import java.io.RandomAccessFile;
24  import java.nio.file.StandardOpenOption;
25  
26  import org.apache.commons.io.build.AbstractOrigin;
27  import org.apache.commons.io.build.AbstractStreamBuilder;
28  
29  /**
30   * An {@link OutputStream} that writes to a {@link RandomAccessFile}.
31   *
32   * @since 2.18.0
33   */
34  public final class RandomAccessFileOutputStream extends OutputStream {
35  
36      // @formatter:off
37      /**
38       * Builds a new {@link RandomAccessFileOutputStream}.
39       * <p>
40       * For example:
41       * </p>
42       * <pre>{@code
43       * RandomAccessFileOutputStream s = RandomAccessFileOutputStream.builder()
44       *   .setFile("myfile.txt")
45       *   .setOpenOptions(StandardOpenOption.SYNC)
46       *   .get();}
47       * </pre>
48       * <p>
49       * The only super's aspect used is buffer size.
50       * </p>
51       *
52       * @see #get()
53       */
54      // @formatter:on
55      public static final class Builder extends AbstractStreamBuilder<RandomAccessFileOutputStream, Builder> {
56  
57          /**
58           * Use {@link RandomAccessFileOutputStream#builder()}.
59           */
60          private Builder() {
61              setOpenOptions(StandardOpenOption.WRITE);
62          }
63  
64          /**
65           * Builds a new {@link RandomAccessFileOutputStream}.
66           * <p>
67           * You must set an aspect that supports {@link RandomAccessFile} or {@link File}, otherwise, this method throws an exception. Only set one of
68           * RandomAccessFile or an origin that can be converted to a File.
69           * </p>
70           * <p>
71           * This builder uses the following aspects:
72           * </p>
73           * <ul>
74           * <li>{@link RandomAccessFile} is the target aspect.</li>
75           * <li>{@link File}</li>
76           * <li>closeOnClose</li>
77           * </ul>
78           *
79           * @return a new instance.
80           * @throws IllegalStateException         if the {@code origin} is {@code null}.
81           * @throws IllegalStateException         if both RandomAccessFile and origin are set.
82           * @throws UnsupportedOperationException if the origin cannot be converted to a {@link RandomAccessFile}.
83           * @throws IOException                   if an I/O error occurs converting to an {@link RandomAccessFile} using {@link #getRandomAccessFile()}.
84           * @see AbstractOrigin#getFile()
85           * @see #getUnchecked()
86           */
87          @Override
88          public RandomAccessFileOutputStream get() throws IOException {
89              return new RandomAccessFileOutputStream(this);
90          }
91  
92      }
93  
94      /**
95       * Constructs a new {@link Builder}.
96       *
97       * @return a new {@link Builder}.
98       */
99      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 }