FileInputStream.java revision 461d0d860814c68154d8dd06d24f94118f33d28a
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.io; 19 20import dalvik.system.CloseGuard; 21 22import java.nio.NioUtils; 23import java.nio.channels.FileChannel; 24import java.util.Arrays; 25import libcore.io.ErrnoException; 26import libcore.io.IoUtils; 27import libcore.io.Libcore; 28import libcore.io.Streams; 29import org.apache.harmony.luni.platform.IFileSystem; 30import org.apache.harmony.luni.platform.Platform; 31import static libcore.io.OsConstants.*; 32 33/** 34 * An input stream that reads bytes from a file. 35 * <pre> {@code 36 * File file = ... 37 * InputStream in = null; 38 * try { 39 * in = new BufferedInputStream(new FileInputStream(file)); 40 * ... 41 * } finally { 42 * if (in != null) { 43 * in.close(); 44 * } 45 * } 46 * }</pre> 47 * 48 * <p>This stream is <strong>not buffered</strong>. Most callers should wrap 49 * this stream with a {@link BufferedInputStream}. 50 * 51 * <p>Use {@link FileReader} to read characters, as opposed to bytes, from a 52 * file. 53 * 54 * @see BufferedInputStream 55 * @see FileOutputStream 56 */ 57public class FileInputStream extends InputStream implements Closeable { 58 59 private final FileDescriptor fd; 60 61 /** The unique file channel. Lazily initialized because it's rarely needed. */ 62 private FileChannel channel; 63 64 private final boolean shouldCloseFd; 65 66 private final CloseGuard guard = CloseGuard.get(); 67 68 /** 69 * Constructs a new {@code FileInputStream} that reads from {@code file}. 70 * 71 * @param file 72 * the file from which this stream reads. 73 * @throws FileNotFoundException 74 * if {@code file} does not exist. 75 */ 76 public FileInputStream(File file) throws FileNotFoundException { 77 if (file == null) { 78 throw new NullPointerException("file == null"); 79 } 80 fd = IoUtils.open(file.getAbsolutePath(), O_RDONLY); 81 shouldCloseFd = true; 82 guard.open("close"); 83 } 84 85 /** 86 * Constructs a new {@code FileInputStream} that reads from {@code fd}. 87 * 88 * @param fd 89 * the FileDescriptor from which this stream reads. 90 * @throws NullPointerException 91 * if {@code fd} is {@code null}. 92 */ 93 public FileInputStream(FileDescriptor fd) { 94 if (fd == null) { 95 throw new NullPointerException("fd == null"); 96 } 97 this.fd = fd; 98 this.shouldCloseFd = false; 99 // Note that we do not call guard.open here because the 100 // FileDescriptor is not owned by the stream. 101 } 102 103 /** 104 * Equivalent to {@code new FileInputStream(new File(path))}. 105 */ 106 public FileInputStream(String path) throws FileNotFoundException { 107 this(new File(path)); 108 } 109 110 @Override 111 public int available() throws IOException { 112 return IoUtils.available(fd); 113 } 114 115 @Override 116 public void close() throws IOException { 117 guard.close(); 118 synchronized (this) { 119 if (channel != null) { 120 channel.close(); 121 } 122 if (shouldCloseFd && fd.valid()) { 123 IoUtils.close(fd); 124 } 125 } 126 } 127 128 /** 129 * Ensures that all resources for this stream are released when it is about 130 * to be garbage collected. 131 * 132 * @throws IOException 133 * if an error occurs attempting to finalize this stream. 134 */ 135 @Override protected void finalize() throws IOException { 136 try { 137 if (guard != null) { 138 guard.warnIfOpen(); 139 } 140 close(); 141 } finally { 142 try { 143 super.finalize(); 144 } catch (Throwable t) { 145 // for consistency with the RI, we must override Object.finalize() to 146 // remove the 'throws Throwable' clause. 147 throw new AssertionError(t); 148 } 149 } 150 } 151 152 /** 153 * Returns a read-only {@link FileChannel} that shares its position with 154 * this stream. 155 */ 156 public FileChannel getChannel() { 157 synchronized (this) { 158 if (channel == null) { 159 channel = NioUtils.newFileChannel(this, fd, O_RDONLY); 160 } 161 return channel; 162 } 163 } 164 165 /** 166 * Returns the underlying file descriptor. 167 */ 168 public final FileDescriptor getFD() throws IOException { 169 return fd; 170 } 171 172 @Override public int read() throws IOException { 173 return Streams.readSingleByte(this); 174 } 175 176 @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 177 return IoUtils.read(fd, buffer, byteOffset, byteCount); 178 } 179 180 @Override 181 public long skip(long byteCount) throws IOException { 182 if (byteCount == 0) { 183 return 0; 184 } 185 if (byteCount < 0) { 186 throw new IOException("byteCount < 0: " + byteCount); 187 } 188 try { 189 // Try lseek(2). That returns the new offset, but we'll throw an 190 // exception if it couldn't perform exactly the seek we asked for. 191 Libcore.os.lseek(fd, byteCount, SEEK_CUR); 192 return byteCount; 193 } catch (ErrnoException errnoException) { 194 if (errnoException.errno == ESPIPE) { 195 // You can't seek on a pipe, so fall back to the superclass' implementation. 196 return super.skip(byteCount); 197 } 198 throw errnoException.rethrowAsIOException(); 199 } 200 } 201} 202