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 }