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