Java8 I/O源码-FileInputStream与FileOutputStream
来源:互联网 发布:mac 怎么创建xlsx文档 编辑:程序博客网 时间:2024/05/21 10:30
今天学习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(); } }}
FileOutputStream
public 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(); }}
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(); } }}
testFileOutputStream执行后,fileStream.txt中的内容为
qrstuvwxQRST
fos.write(new byte[] { 0x61, 0x62, 0x63, 0x64 });// abcdfos.write(new byte[] { 0x65, 0x66, 0x67, 0x68 });// efgh
执行后,文件内容为abcdefgh
FileOutputStream fos2 = new FileOutputStream(file);
执行后,文件内容为空
fos2.write(new byte[] { 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78 });// qrstuvwx
执行后,文件内容为qrstuvwx
FileOutputStream fos3 = new FileOutputStream(file, true);
执行后,文件内容为qrstuvwx
fos3.write(new byte[] { 0x51, 0x52, 0x53, 0x54 });// QRST
执行后,文件内容为qrstuvwxQRST
testFileInputStream执行后后控制台打印内容为:
使用read()读取一个字节:q使用available()获取当前可用字节数:11使用readread(byte[] b,int off,int len)读取5个字节到b中:rstuv使用available()获取当前可用字节数:6使用skip(long n)跳过1个字节使用available()获取当前可用字节数:5
总结
- FileInputStream是文件输入流,用于从文件系统中的某个文件中获得输入字节。FileInputStream用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用FileReader。
- FileOutputStream是文件输出流,用于将数据写入File或FileDescriptor的输出流。FileOutputStream用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用FileWriter。
- Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
- FileInputStream不支持mark方法与set方法。
关于FileInputStream与FileOutputStream就讲到这里,想了解更多内容请参考
- Java8 I/O源码系列专栏-目录
原文地址:CSDN博客-潘威威的博客-http://blog.csdn.net/panweiwei1994/article/details/78277714
本文版权归作者所有,欢迎转载。转载时请在文章明显位置给出原文作者名字(潘威威)及原文链接。请勿将本文用于任何商业用途。
阅读全文
1 0
- Java8 I/O源码-FileInputStream与FileOutputStream
- I/O(一)FileInputStream/FileOutputStream
- Java I/O流-FileInputStream、FileOutputStream
- I/O流之--FileOutputStream 和FileInputStream
- Java8 I/O源码-PipedInputStream与PipedOutputStream
- Java8 I/O源码-BufferedInputStream与BufferedOutputStream
- Java8 I/O源码-DataInputStream与DataOutputStream
- Java8 I/O源码-Reader与Writer
- Java8 I/O源码-CharArrayReader与CharArrayWriter
- Java8 I/O源码-PipedReader与PipedWriter
- Java8 I/O源码-BufferedReader与BufferedWriter
- Java8 I/O源码-InputStreamReader与OutputStreamWriter
- java输入与输出(I/O)(一):FileInputStream、FileOutputStream
- Android使用FileInputStream和FileOutputStream进行文件I/O操作
- Android使用FileInputStream和FileOutputStream进行文件I/O操作
- Android使用FileInputStream和FileOutputStream进行文件I/O操作
- java-I/O File类(3)-FileInputStream/FileOutputStream
- Android使用FileInputStream和FileOutputStream进行文件I/O操作
- ConcurrentHashMap和HashMap的containsKey方法区别
- sql查询语句没有结果时赋值为0
- Codeforces 459E 图上DP 解题报告
- Cg Programming/Unity/Two-Sided Surfaces双面表面
- Angular(1.5)简介,引入,表达式
- Java8 I/O源码-FileInputStream与FileOutputStream
- Android 进程保活--1像素保活
- apktool 回编译说文件名或扩展名太长
- bzoj 1567: [JSOI2008]Blue Mary的战役地图
- 1031. Hello World for U (20)
- Visual Studio Code v1.17发布
- 枚举---Enum类
- Python数据处理2.0.1(列表转字典)
- java实现迪克斯特拉算法