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提高性能
如果觉得文章对你有帮助,就打赏杯咖啡钱呗😊

