A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

今天学习FileInputStream与FileOutputStream。

FileInputStream是文件输入流,用于从文件系统中的某个文件中获得输入字节。FileInputStream用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用FileReader。

FileOutputStream是文件输出流,用于将数据写入File或FileDescriptor的输出流。FileOutputStream用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用FileWriter。

FileInputStream

先学习下FileInputStream的源码。

public class FileInputStream extends InputStream{    //FileInputStream的文件描述符    private final FileDescriptor fd;    //引用文件的路径    private final String path;    //文件通道    private FileChannel channel = null;    //关闭锁    private final Object closeLock = new Object();    //标识流是否关闭    private volatile boolean closed = false;    /**     * 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名name指定。创建一个新FileDescriptor对象来表示此文件连接。     *      * 首先,如果有安全管理器,则用name作为参数调用其checkRead方法。     *     * @param      name   文件系统中的路径名     * @exception  FileNotFoundException  如果该文件不存在,或者它是一个目录,而不是一个常规文件,     * 抑或因为其他某些原因而无法打开进行读取。     */    public FileInputStream(String name) throws FileNotFoundException {        this(name != null ? new File(name) : null);    }    /**     * 通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的File对象file指定。     *      * 参考FileInputStream(String name)的注释     */    public FileInputStream(File file) throws FileNotFoundException {        //获取文件名        String name = (file != null ? file.getPath() : null);        //获取安全管理器        SecurityManager security = System.getSecurityManager();        if (security != null) {            //如果调用线程没有访问指定文件的权限,抛出SecurityException            security.checkRead(name);        }        if (name == null) {            throw new NullPointerException();        }        if (file.isInvalid()) {            throw new FileNotFoundException("Invalid file path");        }        //fd表示此文件连接        fd = new FileDescriptor();        fd.attach(this);        path = name;        //打开文件        open(name);    }    /**     * 通过使用文件描述符fdObj创建一个FileInputStream,该文件描述符表示到文件系统中某个实际文件的现有连接。     */    public FileInputStream(FileDescriptor fdObj) {        SecurityManager security = System.getSecurityManager();        if (fdObj == null) {            throw new NullPointerException();        }        if (security != null) {            security.checkRead(fdObj);        }        fd = fdObj;        path = null;        fd.attach(this);    }    /*     * native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。     * Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。     * JNI是Java本机接口(Java Native Interface),是一个本机编程接口,     * 它是Java软件开发工具箱(Java Software Development Kit,SDK)的一部分。     * JNI允许Java代码使用以其他语言编写的代码和代码库。     * Invocation API(JNI的一部分)可以用来将Java虚拟机(JVM)嵌入到本机应用程序中,     * 从而允许程序员从本机代码内部调用Java代码。     * 所以想要了解open0方法的具体实现只能去查看JVM源码了。     */    private native void open0(String name) throws FileNotFoundException;    // wrap native call to allow instrumentation    /**     * Opens the specified file for reading.     * @param name the name of the file     */    private void open(String name) throws FileNotFoundException {        open0(name);    }    /**     * 从此输入流中读取一个数据字节。     */    public int read() throws IOException {        return read0();    }    /**     * 参考open0(String name)     */    private native int read0() throws IOException;    /**     * 从此输入流中将最多len个字节的数据读入一个起始偏移量为off的byte数组中。     *      * 参考open0(String name)     */    private native int readBytes(byte b[], int off, int len) throws IOException;    /**     * 从此输入流中将最多b.length个字节的数据读入一个起始偏移量为0的byte数组中。     */    public int read(byte b[]) throws IOException {        return readBytes(b, 0, b.length);    }    /**     * 从此输入流中将最多len个字节的数据读入一个起始偏移量为off的byte数组中。     */    public int read(byte b[], int off, int len) throws IOException {        return readBytes(b, off, len);    }    /**     * 从输入流中跳过并丢弃n个字节的数据。     *      * 参考open0(String name)     */    public native long skip(long n) throws IOException;    /**     * 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。     * 参考open0(String name)     */    public native int available() throws IOException;    /**     * 关闭此文件输入流并释放与此流有关的所有系统资源。     * 如果此流有一个与之关联的通道,则关闭该通道。     */    public void close() throws IOException {        synchronized (closeLock) {            if (closed) {                return;            }            closed = true;        }        //如果此流有一个与之关联的通道,则关闭该通道。        if (channel != null) {           channel.close();        }        fd.closeAll(new Closeable() {            public void close() throws IOException {               close0();           }        });    }    /**     * 返回表示到文件系统中实际文件的连接的FileDescriptor对象,该文件系统正被此FileInputStream使用。     */    public final FileDescriptor getFD() throws IOException {        if (fd != null) {            return fd;        }        throw new IOException();    }    /**     * 返回与此文件输入流有关的唯一FileChannel对象。     */    public FileChannel getChannel() {        synchronized (this) {            if (channel == null) {                channel = FileChannelImpl.open(fd, path, true, false, this);            }            return channel;        }    }    //参考open0(String name)    private static native void initIDs();    //参考open0(String name)    private native void close0() throws IOException;    static {        initIDs();    }    /**     * 确保在不再引用文件输入流时调用其close方法。     */    protected void finalize() throws IOException {        if ((fd != null) &&  (fd != FileDescriptor.in)) {            close();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
FileOutputStreampublic class FileOutputStream extends OutputStream{    /**     * 文件描述符     */    private final FileDescriptor fd;    /**     * 标识添加还是替换文件的内容     */    private final boolean append;    /**     * 关联的通道     * 懒加载     */    private FileChannel channel;    //引用文件的路径    private final String path;    //锁    private final Object closeLock = new Object();    //标识流是否关闭    private volatile boolean closed = false;    /**     * 创建一个向具有指定名称的文件中写入数据的输出文件流。     * 创建一个新FileDescriptor对象来表示此文件连接。     * 首先,如果有安全管理器,则用 name 作为参数调用checkWrite方法。     *     * @param      name   文件路径     * @exception  FileNotFoundException  如果文件存在,但它是一个目录,而不是一个常规文件;或者该文件不存在,但无法创建它;抑或因为其他某些原因而无法打开它     * @exception  SecurityException   如果存在安全管理器,且其checkWrite方法拒绝对文件进行写入访问     */    public FileOutputStream(String name) throws FileNotFoundException {        this(name != null ? new File(name) : null, false);    }    /**     * 创建一个向具有指定name的文件中写入数据的输出文件流。如果第二个参数为append为true,则将字节写入文件末尾处,而不是写入文件开始处。     */    public FileOutputStream(String name, boolean append)        throws FileNotFoundException    {        this(name != null ? new File(name) : null, append);    }    /**     * 创建一个向指定File对象表示的文件中写入数据的文件输出流。创建一个新FileDescriptor对象来表示此文件连接。     */    public FileOutputStream(File file) throws FileNotFoundException {        this(file, false);    }    /**     * 创建一个向指定File对象表示的文件中写入数据的文件输出流。如果第二个参数append为true,则将字节写入文件末尾处,而不是写入文件开始处。     */    public FileOutputStream(File file, boolean append)        throws FileNotFoundException    {        String name = (file != null ? file.getPath() : null);        SecurityManager security = System.getSecurityManager();        if (security != null) {            security.checkWrite(name);        }        if (name == null) {            throw new NullPointerException();        }        if (file.isInvalid()) {            throw new FileNotFoundException("Invalid file path");        }        this.fd = new FileDescriptor();        fd.attach(this);        this.append = append;        this.path = name;        open(name, append);    }    /**     * 创建一个向指定文件描述符处写入数据的输出文件流,该文件描述符表示一个到文件系统中的某个实际文件的现有连接。     */    public FileOutputStream(FileDescriptor fdObj) {        SecurityManager security = System.getSecurityManager();        if (fdObj == null) {            throw new NullPointerException();        }        if (security != null) {            security.checkWrite(fdObj);        }        this.fd = fdObj;        this.append = false;        this.path = null;        fd.attach(this);    }    //参考FileInputStream.open0(String name)    private native void open0(String name, boolean append)        throws FileNotFoundException;    private void open(String name, boolean append)        throws FileNotFoundException {        open0(name, append);    }    /**     * 将指定字节写入此文件输出流。     * 参考FileInputStream.open0(String name)     */    private native void write(int b, boolean append) throws IOException;    /**     * 将指定字节写入此文件输出流。     */    public void write(int b) throws IOException {        write(b, append);    }    /**     * 将b.length个字节从指定byte数组写入此文件输出流中     * 参考FileInputStream.open0(String name)     */    private native void writeBytes(byte b[], int off, int len, boolean append)        throws IOException;    /**     * 将指定byte数组中从偏移量off开始的len个字节写入此文件输出流。     */    public void write(byte b[]) throws IOException {        writeBytes(b, 0, b.length, append);    }    /**     * 将指定byte数组中从偏移量off开始的len个字节写入此文件输出流。     */    public void write(byte b[], int off, int len) throws IOException {        writeBytes(b, off, len, append);    }    /**     * 关闭此文件输出流并释放与此流有关的所有系统资源。此文件输出流不能再用于写入字节。     * 如果此流有一个与之关联的通道,则关闭该通道。     */    public void close() throws IOException {        synchronized (closeLock) {            if (closed) {                return;            }            closed = true;        }        if (channel != null) {            channel.close();        }        fd.closeAll(new Closeable() {            public void close() throws IOException {               close0();           }        });    }    /**     * 返回与此流有关的文件描述符。     */     public final FileDescriptor getFD()  throws IOException {        if (fd != null) {            return fd;        }        throw new IOException();     }    /**     * 返回与此文件输出流有关的唯一FileChannel对象。     */    public FileChannel getChannel() {        synchronized (this) {            if (channel == null) {                channel = FileChannelImpl.open(fd, path, false, true, append, this);            }            return channel;        }    }    /**     * 清理到文件的连接,并确保在不再引用此文件输出流时调用此流的close方法。     */    protected void finalize() throws IOException {        if (fd != null) {            if (fd == FileDescriptor.out || fd == FileDescriptor.err) {                flush();            } else {                close();            }        }    }    ////参考FileInputStream.open0(String name)    private native void close0() throws IOException;    //参考FileInputStream.open0(String name)    private static native void initIDs();    static {        initIDs();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
demo

FileInputStream与FileOutputStream与用于操作诸如图像数据之类的原始字节流。要操作字符流,请考虑使用FileReader与FileWriter。

import java.io.File;import java.io.FileDescriptor;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;/** * FileInputStream 和FileOutputStream的API测试类 */public class FileStreamTest {    private static final String FileName = "fileStream.txt";    public static void main(String[] args) {        testFileOutputStream();        testFileInputStream();    }    /**     * FileOutputStream的API测试类     */    private static void testFileOutputStream() {        try {            // FileOutputStream fos = new FileOutputStream("fileStream.txt");            // 创建文件对应File对象            File file = new File(FileName);            // 创建文件对应的FileOutputStream对象,默认是覆盖模式            FileOutputStream fos = new FileOutputStream(file);            fos.write(new byte[] { 0x61, 0x62, 0x63, 0x64 });// abcd            fos.write(new byte[] { 0x65, 0x66, 0x67, 0x68 });// efgh            // 创建文件对应的FileOutputStream对象,默认是覆盖模式            FileOutputStream fos2 = new FileOutputStream(file);            fos2.write(new byte[] { 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78 });// qrstuvwx            // 创建文件对应的FileOutputStream对象,模式为追加模式            FileOutputStream fos3 = new FileOutputStream(file, true);            fos3.write(new byte[] { 0x51, 0x52, 0x53, 0x54 });// QRST            fos.close();            fos2.close();            fos3.close();        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * FileInputStream的API测试函数     */    private static void testFileInputStream() {        try {            File file = new File(FileName);            FileInputStream fis = new FileInputStream(file);            FileDescriptor fd = fis.getFD();            // 根据文件描述符创建FileInputStream对象            FileInputStream fis2 = new FileInputStream(fd);            // 测试read()            System.out.println("使用read()读取一个字节:" + (char) fis.read());            System.out.println("使用available()获取当前可用字节数:" + fis.available());            // 测试read(byte[] b,int off,int len)            byte[] b = new byte[5];            fis.read(b, 0, b.length);            System.out.println("使用readread(byte[] b,int off,int len)读取5个字节到b中:" + new String(b));            System.out.println("使用available()获取当前可用字节数:" + fis.available());            // 测试skip(long byteCount)            System.out.printf("使用skip(long n)跳过%s个字节\n", fis.skip(1));            System.out.println("使用available()获取当前可用字节数:" + fis.available());            fis.close();            fis2.close();        } catch (IOException e) {            e.printStackTrace();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

testFileOutputStream执行后,fileStream.txt中的内容为

qrstuvwxQRST
  • 1
fos.write(new byte[] { 0x61, 0x62, 0x63, 0x64 });// abcdfos.write(new byte[] { 0x65, 0x66, 0x67, 0x68 });// efgh
  • 1
  • 2

执行后,文件内容为abcdefgh

FileOutputStream fos2 = new FileOutputStream(file);
  • 1

执行后,文件内容为空

fos2.write(new byte[] { 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78 });// qrstuvwx
  • 1

执行后,文件内容为qrstuvwx

FileOutputStream fos3 = new FileOutputStream(file, true);
  • 1

执行后,文件内容为qrstuvwx

fos3.write(new byte[] { 0x51, 0x52, 0x53, 0x54 });// QRST
  • 1

执行后,文件内容为qrstuvwxQRST

testFileInputStream执行后后控制台打印内容为:

使用read()读取一个字节:q使用available()获取当前可用字节数:11使用readread(byte[] b,int off,int len)读取5个字节到b中:rstuv使用available()获取当前可用字节数:6使用skip(long n)跳过1个字节使用available()获取当前可用字节数:5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
总结
  • FileInputStream是文件输入流,用于从文件系统中的某个文件中获得输入字节。FileInputStream用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用FileReader。
  • FileOutputStream是文件输出流,用于将数据写入File或FileDescriptor的输出流。FileOutputStream用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用FileWriter。
  • Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
  • FileInputStream不支持mark方法与set方法。

1 个回复

倒序浏览

很不错,受教了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马