简介

FileOutputStream流是指文件字节输出流,专用于输出原始字节流,如图像数据等,其继承OutputStream类,拥有输出流的基本特性

源码分析

  1. package java.io;
  2. import java.nio.channels.FileChannel;
  3. import sun.nio.ch.FileChannelImpl;
  4. /**
  5. * @author Arthur van Hoff
  6. * @see java.io.File
  7. * @see java.io.FileDescriptor
  8. * @see java.io.FileInputStream
  9. * @see java.nio.file.Files#newOutputStream
  10. * @since JDK1.0
  11. */
  12. public
  13. class FileOutputStream extends OutputStream
  14. {
  15. /**
  16. * 文件描述符,打开文件句柄
  17. */
  18. private final FileDescriptor fd;
  19. /**
  20. * 是否在文件末尾追加
  21. */
  22. private final boolean append;
  23. /**
  24. * 文件通道
  25. */
  26. private FileChannel channel;
  27. /**
  28. * 文件路径
  29. */
  30. private final String path;
  31. // 锁机制对象,用于调用close方法时的同步锁对象
  32. private final Object closeLock = new Object();
  33. // 当前输出流是否已关闭
  34. private volatile boolean closed = false;
  35. /**
  36. * 构造方法,传入表示文件路径的字符串,并构造File对象,调用别的构造方法
  37. * @param name the system-dependent filename
  38. * @see java.lang.SecurityManager#checkWrite(java.lang.String)
  39. */
  40. public FileOutputStream(String name) throws FileNotFoundException {
  41. this(name != null ? new File(name) : null, false);
  42. }
  43. /**
  44. * 传入表示文件路径的字符串和是否追加标识,将字符串初始化为File对象,并调用别的构造方法
  45. * @param name the system-dependent file name
  46. * @param append if <code>true</code>, then bytes will be written
  47. * to the end of the file rather than the beginning
  48. * @see java.lang.SecurityManager#checkWrite(java.lang.String)
  49. * @since JDK1.1
  50. */
  51. public FileOutputStream(String name, boolean append)
  52. throws FileNotFoundException
  53. {
  54. this(name != null ? new File(name) : null, append);
  55. }
  56. /**
  57. * 传入File对象,调用别的构造方法
  58. * @param file the file to be opened for writing.
  59. * @see java.io.File#getPath()
  60. * @see java.lang.SecurityException
  61. * @see java.lang.SecurityManager#checkWrite(java.lang.String)
  62. */
  63. public FileOutputStream(File file) throws FileNotFoundException {
  64. this(file, false);
  65. }
  66. /**
  67. * 传入文件对象和是否追加标识,构造输出流对象
  68. * @param file the file to be opened for writing.
  69. * @param append if <code>true</code>, then bytes will be written
  70. * to the end of the file rather than the beginning
  71. * @see java.io.File#getPath()
  72. * @see java.lang.SecurityException
  73. * @see java.lang.SecurityManager#checkWrite(java.lang.String)
  74. * @since 1.4
  75. */
  76. public FileOutputStream(File file, boolean append)
  77. throws FileNotFoundException
  78. {
  79. // 合法验证
  80. String name = (file != null ? file.getPath() : null);
  81. SecurityManager security = System.getSecurityManager();
  82. if (security != null) {
  83. security.checkWrite(name);
  84. }
  85. if (name == null) {
  86. throw new NullPointerException();
  87. }
  88. if (file.isInvalid()) {
  89. throw new FileNotFoundException("Invalid file path");
  90. }
  91. // 正常赋值
  92. this.fd = new FileDescriptor();
  93. fd.attach(this);
  94. this.append = append;
  95. this.path = name;
  96. // 根据文件路径和是否追加标识构建输出流
  97. open(name, append);
  98. }
  99. /**
  100. * 创建一个向指定文件描述符处写入数据的输出文件流
  101. * @param fdObj the file descriptor to be opened for writing
  102. * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
  103. */
  104. public FileOutputStream(FileDescriptor fdObj) {
  105. SecurityManager security = System.getSecurityManager();
  106. if (fdObj == null) {
  107. throw new NullPointerException();
  108. }
  109. if (security != null) {
  110. security.checkWrite(fdObj);
  111. }
  112. this.fd = fdObj;
  113. this.append = false;
  114. this.path = null;
  115. fd.attach(this);
  116. }
  117. /**
  118. * native方法,开启输出流
  119. * @param name name of file to be opened
  120. * @param append whether the file is to be opened in append mode
  121. */
  122. private native void open0(String name, boolean append)
  123. throws FileNotFoundException;
  124. // wrap native call to allow instrumentation
  125. /**
  126. * 打开文件,并标识追加还是覆盖
  127. * @param name name of file to be opened
  128. * @param append whether the file is to be opened in append mode
  129. */
  130. private void open(String name, boolean append)
  131. throws FileNotFoundException {
  132. open0(name, append);
  133. }
  134. /**
  135. * native方法,向文件输出一个字节内容,并指定是追加到原有内容后面还是覆盖原有内容
  136. * @param b the byte to be written. 需要输出的字节
  137. * @param append {@code true} if the write operation first
  138. * advances the position to the end of file 是否追加
  139. */
  140. private native void write(int b, boolean append) throws IOException;
  141. /**
  142. * 向文件输出一个字节内容
  143. * @param b the byte to be written.
  144. * @exception IOException if an I/O error occurs.
  145. */
  146. public void write(int b) throws IOException {
  147. write(b, append);
  148. }
  149. /**
  150. * native方法,向文件输出byte数组从off下标之后的len个字节,并指定是否追加
  151. * @param b the data to be written 字节数组
  152. * @param off the start offset in the data 输出内容在字节数组的起始位置
  153. * @param len the number of bytes that are written 输出多少个字节
  154. * @param append {@code true} to first advance the position to the
  155. * end of file 是否追加
  156. */
  157. private native void writeBytes(byte b[], int off, int len, boolean append)
  158. throws IOException;
  159. /**
  160. * 向文件输出字节数组的全部内容
  161. * @param b the data.
  162. */
  163. public void write(byte b[]) throws IOException {
  164. writeBytes(b, 0, b.length, append);
  165. }
  166. /**
  167. * 向文件输出字节数组从off下标开始的len个字节
  168. * @param b the data.
  169. * @param off the start offset in the data.
  170. * @param len the number of bytes to write.
  171. */
  172. public void write(byte b[], int off, int len) throws IOException {
  173. writeBytes(b, off, len, append);
  174. }
  175. /**
  176. * 关闭输出流
  177. * @revised 1.4
  178. * @spec JSR-51
  179. */
  180. public void close() throws IOException {
  181. // 线程同步
  182. synchronized (closeLock) {
  183. if (closed) {
  184. return;
  185. }
  186. closed = true;
  187. }
  188. // 关闭通道
  189. if (channel != null) {
  190. channel.close();
  191. }
  192. // 文件句柄释放
  193. fd.closeAll(new Closeable() {
  194. public void close() throws IOException {
  195. close0();
  196. }
  197. });
  198. }
  199. /**
  200. * 获取文件描述符(文件句柄)
  201. * @return the <code>FileDescriptor</code> object that represents
  202. * the connection to the file in the file system being used
  203. * by this <code>FileOutputStream</code> object.
  204. * @see java.io.FileDescriptor
  205. */
  206. public final FileDescriptor getFD() throws IOException {
  207. if (fd != null) {
  208. return fd;
  209. }
  210. throw new IOException();
  211. }
  212. /**
  213. * 获取通道
  214. * @return the file channel associated with this file output stream
  215. * @since 1.4
  216. * @spec JSR-51
  217. */
  218. public FileChannel getChannel() {
  219. synchronized (this) {
  220. if (channel == null) {
  221. channel = FileChannelImpl.open(fd, path, false, true, append, this);
  222. }
  223. return channel;
  224. }
  225. }
  226. /**
  227. * 释放资源,同时刷新缓存,强制将缓存中的内容写入文件
  228. * @see java.io.FileInputStream#close()
  229. */
  230. protected void finalize() throws IOException {
  231. if (fd != null) {
  232. if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
  233. flush();
  234. } else {
  235. /*
  236. */
  237. close();
  238. }
  239. }
  240. }
  241. private native void close0() throws IOException;
  242. private static native void initIDs();
  243. static {
  244. initIDs();
  245. }
  246. }

简单使用

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();
                }
            }
        }

    }
}

输出结果:
图片.png