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.IOException;
021import java.io.OutputStream;
022import java.io.RandomAccessFile;
023import java.nio.file.StandardOpenOption;
024import java.util.Objects;
025
026import org.apache.commons.io.build.AbstractStreamBuilder;
027
028/**
029 * An {@link OutputStream} that writes to a {@link RandomAccessFile}.
030 *
031 * @since 2.18.0
032 */
033public final class RandomAccessFileOutputStream extends OutputStream {
034
035    // @formatter:off
036    /**
037     * Builds a new {@link RandomAccessFileOutputStream}.
038     * <p>
039     * For example:
040     * </p>
041     * <pre>{@code
042     * RandomAccessFileOutputStream s = RandomAccessFileOutputStream.builder()
043     *   .setFile("myfile.txt")
044     *   .setOpenOptions(StandardOpenOption.SYNC)
045     *   .get();}
046     * </pre>
047     * <p>
048     * The only super's aspect used is buffer size.
049     * </p>
050     *
051     * @see #get()
052     */
053    // @formatter:on
054    public final static class Builder extends AbstractStreamBuilder<RandomAccessFileOutputStream, Builder> {
055
056        /**
057         * Use {@link RandomAccessFileOutputStream#builder()}.
058         */
059        private Builder() {
060            setOpenOptions(StandardOpenOption.WRITE);
061        }
062
063        @SuppressWarnings("resource")
064        @Override
065        public RandomAccessFileOutputStream get() throws IOException {
066            return new RandomAccessFileOutputStream(getRandomAccessFile());
067        }
068
069    }
070
071    /**
072     * Constructs a new {@link Builder}.
073     *
074     * @return a new {@link Builder}.
075     */
076    public static Builder builder() {
077        return new Builder();
078    }
079
080    private final RandomAccessFile randomAccessFile;
081
082    private RandomAccessFileOutputStream(final RandomAccessFile randomAccessFile) {
083        this.randomAccessFile = Objects.requireNonNull(randomAccessFile);
084    }
085
086    @Override
087    public void close() throws IOException {
088        this.randomAccessFile.close();
089        super.close();
090    }
091
092    @SuppressWarnings("resource")
093    @Override
094    public void flush() throws IOException {
095        randomAccessFile.getChannel().force(true);
096        super.flush();
097    }
098
099    @Override
100    public void write(final int b) throws IOException {
101        randomAccessFile.write(b);
102    }
103
104}