JDK源码阅读-FileOutputStream
FileOutputStream
用户打开文件并获取输出流。
打开文件
1 | public FileOutputStream(File file, boolean append) |
1 | // jdk/src/solaris/native/java/io/FileOutputStream_md.c |
fileOpen
之后的流程与FileInputStream
的一致,可以参考JDK源码阅读-FileInputStream
写文件
FileOutputStream
提供了三个write函数:
1 | public void write(int b) throws IOException { |
1 | // jdk/src/solaris/native/java/io/FileOutputStream_md.c |
1 | // jdk/src/share/native/java/io/io_util.c |
IO_Write
/IO_Append
虽然看起来是两个不同的函数,其实是两个不同的宏定义,指向同一个函数handleWrite
:
1 | // jdk/src/solaris/native/java/io/io_util_md.h |
handleWrite
中调用write
系统调用写入数据:
1 | // jdk/src/solaris/native/java/io/io_util_md.c |
FileOutputStream#write(byte[], int, int)
的主要流程:
- 检查参数是否合法(byte数组不能为空,off和len没有越界)
- 判断读取的长度,如果等于0直接返回0,如果大于BUF_SIZE需要在堆空间申请内存,如果
0<len<=BUF_SIZE
则直接在使用栈空间的缓存 - 从Java空间的byte数组复制数据到中C空间的char数组中
- 调用
write
系统调用写文件内容到系统中
重要收获:
- 使用
FileOutputStream#write(byte[], int, int)
写入的长度,len一定不能大于8192!因为在小于8192时,会直接利用栈空间的char数组,如果大于,则需要调用malloc申请内存,并且还需要free释放内存,这是非常消耗时间的。 - 相比于直接使用系统调用,Java的写入会多一次拷贝!
关闭文件
1 | public void close() throws IOException { |
FileOutputStream
关闭文件的逻辑和FileInputStream
关闭文件的逻辑是一样的,参考JDK源码阅读-FileDescriptor
总结
FileOutputStream
打开文件使用open
系统调用FileOutputStream
写入文件使用write
系统调用FileOutputStream
关闭文件使用close
系统调用- 使用
FileOutputStream#write(byte[], int, int)
写入的长度,len一定不能大于8192!因为在小于8192时,会直接利用栈空间的char数组,如果大于,则需要调用malloc申请内存,并且还需要free释放内存,这是非常消耗时间的。 - 相比于直接使用系统调用,Java的写入会多一次拷贝!
FileOutputStream#write
是无缓冲的,所以每次调用对对应一次系统调用,可能会有较低的性能,需要结合BufferedOutputStream
提高性能
如果觉得文章对你有帮助,就打赏杯咖啡钱呗😊