今天学习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(); } }}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执行后,文件内容为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| 欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |