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; 240b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge; 2599a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughesimport libcore.io.IoUtils; 26cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughesimport static libcore.io.OsConstants.*; 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 55b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes private FileDescriptor fd; 56b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes private final boolean shouldClose; 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 58024784c977a744708ab0bcefc4337d491e429937Jesse Wilson /** The unique file channel. Lazily initialized because it's rarely needed. */ 59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private FileChannel channel; 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 61024784c977a744708ab0bcefc4337d491e429937Jesse Wilson /** File access mode */ 62024784c977a744708ab0bcefc4337d491e429937Jesse Wilson private final int mode; 63024784c977a744708ab0bcefc4337d491e429937Jesse Wilson 6412f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom private final CloseGuard guard = CloseGuard.get(); 65f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 675722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * Constructs a new {@code FileOutputStream} that writes to {@code file}. The file will be 685722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * truncated if it exists, and created if it doesn't exist. 69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 70024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * @throws FileNotFoundException if file cannot be opened for writing. 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public FileOutputStream(File file) throws FileNotFoundException { 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(file, false); 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 775722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * Constructs a new {@code FileOutputStream} that writes to {@code file}. 785722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * If {@code append} is true and the file already exists, it will be appended to; otherwise 795722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * it will be truncated. The file will be created if it does not exist. 80f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 81024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * @throws FileNotFoundException if the file cannot be opened for writing. 82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 83ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes public FileOutputStream(File file, boolean append) throws FileNotFoundException { 84462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes if (file == null) { 85462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes throw new NullPointerException("file == null"); 86462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes } 87cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughes this.mode = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC); 880b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes this.fd = IoBridge.open(file.getAbsolutePath(), mode); 89b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes this.shouldClose = true; 9012f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom this.guard.open("close"); 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 94024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * Constructs a new {@code FileOutputStream} that writes to {@code fd}. 95f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 96024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * @throws NullPointerException if {@code fd} is null. 97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public FileOutputStream(FileDescriptor fd) { 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (fd == null) { 100462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes throw new NullPointerException("fd == null"); 101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.fd = fd; 103b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes this.shouldClose = false; 104cdf7a1f942469221bcfd63d9cdf71851b011eaf0Elliott Hughes this.mode = O_WRONLY; 10552724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes this.channel = NioUtils.newFileChannel(this, fd, mode); 106bd3f08d95b31543b5f1fe3d93594efc9c8a2879bBrian Carlstrom // Note that we do not call guard.open here because the 107bd3f08d95b31543b5f1fe3d93594efc9c8a2879bBrian Carlstrom // FileDescriptor is not owned by the stream. 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1115722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * Constructs a new {@code FileOutputStream} that writes to {@code path}. The file will be 1125722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * truncated if it exists, and created if it doesn't exist. 1135722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * 1145722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * @throws FileNotFoundException if file cannot be opened for writing. 115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 116024784c977a744708ab0bcefc4337d491e429937Jesse Wilson public FileOutputStream(String path) throws FileNotFoundException { 117024784c977a744708ab0bcefc4337d491e429937Jesse Wilson this(path, false); 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1215722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * Constructs a new {@code FileOutputStream} that writes to {@code path}. 1225722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * If {@code append} is true and the file already exists, it will be appended to; otherwise 1235722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * it will be truncated. The file will be created if it does not exist. 1245722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * 1255722fb8a3c56310ad3e9394e7bd9bb0fd17917a9Elliott Hughes * @throws FileNotFoundException if the file cannot be opened for writing. 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 127024784c977a744708ab0bcefc4337d491e429937Jesse Wilson public FileOutputStream(String path, boolean append) throws FileNotFoundException { 128024784c977a744708ab0bcefc4337d491e429937Jesse Wilson this(new File(path), append); 129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void close() throws IOException { 13312f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom guard.close(); 134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project synchronized (this) { 135024784c977a744708ab0bcefc4337d491e429937Jesse Wilson if (channel != null) { 136024784c977a744708ab0bcefc4337d491e429937Jesse Wilson channel.close(); 137024784c977a744708ab0bcefc4337d491e429937Jesse Wilson } 138b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes if (shouldClose) { 139b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes IoUtils.close(fd); 140b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes } else { 141b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes // An owned fd has been invalidated by IoUtils.close, but 142b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes // we need to explicitly stop using an unowned fd (http://b/4361076). 143b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes fd = new FileDescriptor(); 144b1f55cb6f95928be969a8fe5c7447e13f14d0a68Elliott Hughes } 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 148e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom @Override protected void finalize() throws IOException { 149024784c977a744708ab0bcefc4337d491e429937Jesse Wilson try { 15012f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom if (guard != null) { 15112f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom guard.warnIfOpen(); 15212f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom } 153e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom close(); 154e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom } finally { 155e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom try { 156e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom super.finalize(); 157e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom } catch (Throwable t) { 15863fcdd7e833df417cfbd60961a5167ce637f3071Brian Carlstrom // for consistency with the RI, we must override Object.finalize() to 15963fcdd7e833df417cfbd60961a5167ce637f3071Brian Carlstrom // remove the 'throws Throwable' clause. 160e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom throw new AssertionError(t); 161e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom } 162024784c977a744708ab0bcefc4337d491e429937Jesse Wilson } 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 166024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * Returns a write-only {@link FileChannel} that shares its position with 167024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * this stream. 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public FileChannel getChannel() { 170024784c977a744708ab0bcefc4337d491e429937Jesse Wilson synchronized (this) { 171024784c977a744708ab0bcefc4337d491e429937Jesse Wilson if (channel == null) { 17252724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes channel = NioUtils.newFileChannel(this, fd, mode); 173024784c977a744708ab0bcefc4337d491e429937Jesse Wilson } 174024784c977a744708ab0bcefc4337d491e429937Jesse Wilson return channel; 175024784c977a744708ab0bcefc4337d491e429937Jesse Wilson } 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 179024784c977a744708ab0bcefc4337d491e429937Jesse Wilson * Returns the underlying file descriptor. 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final FileDescriptor getFD() throws IOException { 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return fd; 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 18678c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException { 1870b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes IoBridge.write(fd, buffer, byteOffset, byteCount); 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void write(int oneByte) throws IOException { 19226c7025a7a919044771fb89031161bd26fe03032Elliott Hughes write(new byte[] { (byte) oneByte }, 0, 1); 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 195