简介
FileOutputStream流是指文件字节输出流,专用于输出原始字节流,如图像数据等,其继承OutputStream类,拥有输出流的基本特性
源码分析
package java.io;
import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;
/**
* @author Arthur van Hoff
* @see java.io.File
* @see java.io.FileDescriptor
* @see java.io.FileInputStream
* @see java.nio.file.Files#newOutputStream
* @since JDK1.0
*/
public
class FileOutputStream extends OutputStream
{
/**
* 文件描述符,打开文件句柄
*/
private final FileDescriptor fd;
/**
* 是否在文件末尾追加
*/
private final boolean append;
/**
* 文件通道
*/
private FileChannel channel;
/**
* 文件路径
*/
private final String path;
// 锁机制对象,用于调用close方法时的同步锁对象
private final Object closeLock = new Object();
// 当前输出流是否已关闭
private volatile boolean closed = false;
/**
* 构造方法,传入表示文件路径的字符串,并构造File对象,调用别的构造方法
* @param name the system-dependent filename
* @see java.lang.SecurityManager#checkWrite(java.lang.String)
*/
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
/**
* 传入表示文件路径的字符串和是否追加标识,将字符串初始化为File对象,并调用别的构造方法
* @param name the system-dependent file name
* @param append if <code>true</code>, then bytes will be written
* to the end of the file rather than the beginning
* @see java.lang.SecurityManager#checkWrite(java.lang.String)
* @since JDK1.1
*/
public FileOutputStream(String name, boolean append)
throws FileNotFoundException
{
this(name != null ? new File(name) : null, append);
}
/**
* 传入File对象,调用别的构造方法
* @param file the file to be opened for writing.
* @see java.io.File#getPath()
* @see java.lang.SecurityException
* @see java.lang.SecurityManager#checkWrite(java.lang.String)
*/
public FileOutputStream(File file) throws FileNotFoundException {
this(file, false);
}
/**
* 传入文件对象和是否追加标识,构造输出流对象
* @param file the file to be opened for writing.
* @param append if <code>true</code>, then bytes will be written
* to the end of the file rather than the beginning
* @see java.io.File#getPath()
* @see java.lang.SecurityException
* @see java.lang.SecurityManager#checkWrite(java.lang.String)
* @since 1.4
*/
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);
}
/**
* 创建一个向指定文件描述符处写入数据的输出文件流
* @param fdObj the file descriptor to be opened for writing
* @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
*/
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);
}
/**
* native方法,开启输出流
* @param name name of file to be opened
* @param append whether the file is to be opened in append mode
*/
private native void open0(String name, boolean append)
throws FileNotFoundException;
// wrap native call to allow instrumentation
/**
* 打开文件,并标识追加还是覆盖
* @param name name of file to be opened
* @param append whether the file is to be opened in append mode
*/
private void open(String name, boolean append)
throws FileNotFoundException {
open0(name, append);
}
/**
* native方法,向文件输出一个字节内容,并指定是追加到原有内容后面还是覆盖原有内容
* @param b the byte to be written. 需要输出的字节
* @param append {@code true} if the write operation first
* advances the position to the end of file 是否追加
*/
private native void write(int b, boolean append) throws IOException;
/**
* 向文件输出一个字节内容
* @param b the byte to be written.
* @exception IOException if an I/O error occurs.
*/
public void write(int b) throws IOException {
write(b, append);
}
/**
* native方法,向文件输出byte数组从off下标之后的len个字节,并指定是否追加
* @param b the data to be written 字节数组
* @param off the start offset in the data 输出内容在字节数组的起始位置
* @param len the number of bytes that are written 输出多少个字节
* @param append {@code true} to first advance the position to the
* end of file 是否追加
*/
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
/**
* 向文件输出字节数组的全部内容
* @param b the data.
*/
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length, append);
}
/**
* 向文件输出字节数组从off下标开始的len个字节
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}
/**
* 关闭输出流
* @revised 1.4
* @spec JSR-51
*/
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();
}
});
}
/**
* 获取文件描述符(文件句柄)
* @return the <code>FileDescriptor</code> object that represents
* the connection to the file in the file system being used
* by this <code>FileOutputStream</code> object.
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
if (fd != null) {
return fd;
}
throw new IOException();
}
/**
* 获取通道
* @return the file channel associated with this file output stream
* @since 1.4
* @spec JSR-51
*/
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, path, false, true, append, this);
}
return channel;
}
}
/**
* 释放资源,同时刷新缓存,强制将缓存中的内容写入文件
* @see java.io.FileInputStream#close()
*/
protected void finalize() throws IOException {
if (fd != null) {
if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
/*
*/
close();
}
}
}
private native void close0() throws IOException;
private static native void initIDs();
static {
initIDs();
}
}
简单使用
package com.java.io;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @description
* @date: 2021-01-18 22:01
*/
public class FileOutputStreamExample {
public static void main(String[] args) {
commonExample();
}
public static void commonExample() {
String filePath = "D:\\IDEAWorkSpace\\JAVALearn\\io\\src\\resource\\fileOut.txt";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(filePath);
fileOutputStream.write("Test Message".getBytes());
// 默认是追加到Test Message后面
fileOutputStream.write(" Test Text".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(null != fileOutputStream){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
输出结果: