1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.io;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport dalvik.system.CloseGuard;
21ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughesimport java.nio.NioUtils;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.FileChannel;
230b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge;
24f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller
255d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.*;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
28024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * An output stream that writes bytes to a file. If the output file exists, it
29024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * can be replaced or appended to. If it does not exist, a new file will be
30024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * created.
31024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * <pre>   {@code
32024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   File file = ...
33024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   OutputStream out = null;
34024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   try {
35024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     out = new BufferedOutputStream(new FileOutputStream(file));
36024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     ...
37024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   } finally {
38024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     if (out != null) {
39024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *       out.close();
40024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     }
41024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   }
42024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * }</pre>
43024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *
44024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * <p>This stream is <strong>not buffered</strong>. Most callers should wrap
45024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * this stream with a {@link BufferedOutputStream}.
46024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *
47024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * <p>Use {@link FileWriter} to write characters, as opposed to bytes, to a file.
48f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see BufferedOutputStream
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see FileInputStream
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
52d45b1db47a0258ecb532671e87ebd5ec3df28498Elliott Hughespublic class FileOutputStream extends OutputStream {
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
54b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes    private FileDescriptor fd;
55b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes    private final boolean shouldClose;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    /** The unique file channel. Lazily initialized because it's rarely needed. */
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private FileChannel channel;
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
60024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    /** File access mode */
61024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    private final int mode;
62024784c977a744708ab0bcefc4337d491e429937Jesse Wilson
6312f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
64f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
665722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * Constructs a new {@code FileOutputStream} that writes to {@code file}. The file will be
675722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * truncated if it exists, and created if it doesn't exist.
68f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
69024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @throws FileNotFoundException if file cannot be opened for writing.
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public FileOutputStream(File file) throws FileNotFoundException {
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(file, false);
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
765722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * Constructs a new {@code FileOutputStream} that writes to {@code file}.
775722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * If {@code append} is true and the file already exists, it will be appended to; otherwise
785722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * it will be truncated. The file will be created if it does not exist.
79f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
80024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @throws FileNotFoundException if the file cannot be opened for writing.
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
82ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes    public FileOutputStream(File file, boolean append) throws FileNotFoundException {
83462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes        if (file == null) {
84462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes            throw new NullPointerException("file == null");
85462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes        }
86cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughes        this.mode = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
875fecee2da855e92afbcba3a231f4685a56f17967Narayan Kamath        this.fd = IoBridge.open(file.getPath(), mode);
88b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes        this.shouldClose = true;
8912f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom        this.guard.open("close");
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
93024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Constructs a new {@code FileOutputStream} that writes to {@code fd}.
94f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
95024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @throws NullPointerException if {@code fd} is null.
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public FileOutputStream(FileDescriptor fd) {
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fd == null) {
99462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes            throw new NullPointerException("fd == null");
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.fd = fd;
102b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes        this.shouldClose = false;
103cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughes        this.mode = O_WRONLY;
10452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes        this.channel = NioUtils.newFileChannel(this, fd, mode);
105bd3f08d95b31543b5f1fe3d93594efc9c8a2879bBrian Carlstrom        // Note that we do not call guard.open here because the
106bd3f08d95b31543b5f1fe3d93594efc9c8a2879bBrian Carlstrom        // FileDescriptor is not owned by the stream.
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1105722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * Constructs a new {@code FileOutputStream} that writes to {@code path}. The file will be
1115722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * truncated if it exists, and created if it doesn't exist.
1125722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     *
1135722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * @throws FileNotFoundException if file cannot be opened for writing.
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
115024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    public FileOutputStream(String path) throws FileNotFoundException {
116024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        this(path, false);
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1205722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * Constructs a new {@code FileOutputStream} that writes to {@code path}.
1215722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * If {@code append} is true and the file already exists, it will be appended to; otherwise
1225722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * it will be truncated. The file will be created if it does not exist.
1235722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     *
1245722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes     * @throws FileNotFoundException if the file cannot be opened for writing.
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
126024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    public FileOutputStream(String path, boolean append) throws FileNotFoundException {
127024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        this(new File(path), append);
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void close() throws IOException {
13212f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom        guard.close();
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
134024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            if (channel != null) {
135024784c977a744708ab0bcefc4337d491e429937Jesse Wilson                channel.close();
136024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            }
137b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes            if (shouldClose) {
138f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller                IoBridge.closeAndSignalBlockedThreads(fd);
139b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes            } else {
140b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes                // An owned fd has been invalidated by IoUtils.close, but
141b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes                // we need to explicitly stop using an unowned fd (http://b/4361076).
142b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes                fd = new FileDescriptor();
143b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes            }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
147e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws IOException {
148024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        try {
14912f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
15012f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
15112f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
152e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            close();
153e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
154e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            try {
155e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                super.finalize();
156e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            } catch (Throwable t) {
15763fcdd7e833df417cfbd60961a5167ce637f3071Brian Carlstrom                // for consistency with the RI, we must override Object.finalize() to
15863fcdd7e833df417cfbd60961a5167ce637f3071Brian Carlstrom                // remove the 'throws Throwable' clause.
159e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                throw new AssertionError(t);
160e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            }
161024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        }
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
165024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Returns a write-only {@link FileChannel} that shares its position with
166024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * this stream.
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public FileChannel getChannel() {
169024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        synchronized (this) {
170024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            if (channel == null) {
17152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes                channel = NioUtils.newFileChannel(this, fd, mode);
172024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            }
173024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            return channel;
174024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        }
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
178024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Returns the underlying file descriptor.
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final FileDescriptor getFD() throws IOException {
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return fd;
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
18578c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes    public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException {
1860b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoBridge.write(fd, buffer, byteOffset, byteCount);
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void write(int oneByte) throws IOException {
19126c7025a7a919044771fb89031161bd26fe03032Elliott Hughes        write(new byte[] { (byte) oneByte }, 0, 1);
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
194