FileOutputStream.java revision 52724d3ebd4ccaaa4b9f5576e329d4272cde8ea9
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;
23a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
2499a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughesimport libcore.io.IoUtils;
25cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughesimport static libcore.io.OsConstants.*;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.platform.Platform;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
29024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * An output stream that writes bytes to a file. If the output file exists, it
30024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * can be replaced or appended to. If it does not exist, a new file will be
31024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * created.
32024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * <pre>   {@code
33024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   File file = ...
34024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   OutputStream out = null;
35024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   try {
36024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     out = new BufferedOutputStream(new FileOutputStream(file));
37024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     ...
38024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   } finally {
39024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     if (out != null) {
40024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *       out.close();
41024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *     }
42024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *   }
43024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * }</pre>
44024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *
45024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * <p>This stream is <strong>not buffered</strong>. Most callers should wrap
46024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * this stream with a {@link BufferedOutputStream}.
47024784c977a744708ab0bcefc4337d491e429937Jesse Wilson *
48024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * <p>Use {@link FileWriter} to write characters, as opposed to bytes, to a file.
49f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see BufferedOutputStream
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see FileInputStream
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class FileOutputStream extends OutputStream implements Closeable {
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
55024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    private final FileDescriptor fd;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    private final boolean shouldCloseFd;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
59024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    /** The unique file channel. Lazily initialized because it's rarely needed. */
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private FileChannel channel;
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
62024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    /** File access mode */
63024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    private final int mode;
64024784c977a744708ab0bcefc4337d491e429937Jesse Wilson
6512f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
66f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
68024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Constructs a new {@code FileOutputStream} that writes to {@code file}.
69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
70024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @param file the file to which this stream writes.
71024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @throws FileNotFoundException if file cannot be opened for writing.
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public FileOutputStream(File file) throws FileNotFoundException {
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this(file, false);
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
78024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Constructs a new {@code FileOutputStream} that writes to {@code file},
79024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * creating it if necessary. If {@code append} is true and the file already
80024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * exists, it will be appended to. Otherwise a new file will be created.
81f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
82024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @param file the file to which this stream writes.
83024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @param append true to append to an existing file.
84024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @throws FileNotFoundException if the file cannot be opened for writing.
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
86ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes    public FileOutputStream(File file, boolean append) throws FileNotFoundException {
87024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        this.fd = new FileDescriptor();
88cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughes        this.mode = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
89024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        this.fd.descriptor = Platform.FILE_SYSTEM.open(file.getAbsolutePath(), mode);
90024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        this.shouldCloseFd = true;
9112f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom        this.guard.open("close");
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
95024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Constructs a new {@code FileOutputStream} that writes to {@code fd}.
96f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
97024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @param fd the FileDescriptor to which this stream writes.
98024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * @throws NullPointerException if {@code fd} is null.
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public FileOutputStream(FileDescriptor fd) {
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (fd == null) {
102b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new NullPointerException();
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.fd = fd;
105024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        this.shouldCloseFd = false;
106cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughes        this.mode = O_WRONLY;
10752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes        this.channel = NioUtils.newFileChannel(this, fd, mode);
108bd3f08d95b31543b5f1fe3d93594efc9c8a2879bBrian Carlstrom        // Note that we do not call guard.open here because the
109bd3f08d95b31543b5f1fe3d93594efc9c8a2879bBrian Carlstrom        // FileDescriptor is not owned by the stream.
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
113024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Equivalent to {@code new FileOutputStream(new File(path), false)}.
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    /**
120024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Equivalent to {@code new FileOutputStream(new File(path), append)}.
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
122024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    public FileOutputStream(String path, boolean append) throws FileNotFoundException {
123024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        this(new File(path), append);
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void close() throws IOException {
12812f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom        guard.close();
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
130024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            if (channel != null) {
131024784c977a744708ab0bcefc4337d491e429937Jesse Wilson                channel.close();
132024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            }
133024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            if (shouldCloseFd && fd.valid()) {
13499a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughes                IoUtils.close(fd);
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
139e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws IOException {
140024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        try {
14112f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
14212f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
14312f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
144e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            close();
145e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
146e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            try {
147e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                super.finalize();
148e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            } catch (Throwable t) {
14963fcdd7e833df417cfbd60961a5167ce637f3071Brian Carlstrom                // for consistency with the RI, we must override Object.finalize() to
15063fcdd7e833df417cfbd60961a5167ce637f3071Brian Carlstrom                // remove the 'throws Throwable' clause.
151e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                throw new AssertionError(t);
152e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            }
153024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        }
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
157024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Returns a write-only {@link FileChannel} that shares its position with
158024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * this stream.
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public FileChannel getChannel() {
161024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        synchronized (this) {
162024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            if (channel == null) {
16352724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes                channel = NioUtils.newFileChannel(this, fd, mode);
164024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            }
165024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            return channel;
166024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        }
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
170024784c977a744708ab0bcefc4337d491e429937Jesse Wilson     * Returns the underlying file descriptor.
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final FileDescriptor getFD() throws IOException {
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return fd;
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
177a1603838fe9e865575c87982e32c6343740e464cElliott Hughes    public void write(byte[] buffer, int offset, int byteCount) throws IOException {
178a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
179a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        if (byteCount == 0) {
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
182024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        checkOpen();
183a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        Platform.FILE_SYSTEM.write(fd.descriptor, buffer, offset, byteCount);
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void write(int oneByte) throws IOException {
188024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        checkOpen();
189024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        byte[] buffer = { (byte) oneByte };
190024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        Platform.FILE_SYSTEM.write(fd.descriptor, buffer, 0, 1);
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
193024784c977a744708ab0bcefc4337d491e429937Jesse Wilson    private synchronized void checkOpen() throws IOException {
194024784c977a744708ab0bcefc4337d491e429937Jesse Wilson        if (!fd.valid()) {
195024784c977a744708ab0bcefc4337d491e429937Jesse Wilson            throw new IOException("stream is closed");
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
199