为什么服务器里总有一堆 .tmp 临时文件?
为什么服务器里总有一堆 .tmp 临时文件?
在做文件上传功能时,你可能会发现一个现象:无论最终要把文件存到哪里,服务器似乎总喜欢先在本地偷偷存一个 .tmp 临时文件。
这到底是多此一举,还是由于物理定律的限制?
特别是当你引入“分片上传”功能后,这个临时文件似乎变得无法回避。今天我们就来聊聊这背后的底层逻辑:流(Stream)与随机访问(Random Access)的战争。
一、 普通上传:理论上是可以“直通”的
首先,我们需要理解计算机是如何传输数据的。
当你使用最传统的表单上传(MultipartFile)一个文件时,数据就像自来水一样,通过网线(水管)流向你的服务器。这在计算机里被称为 IO流(InputStream)。
“流”的特性
流最大的特性是:一去不复返,只能顺序读。
就像水龙头里的水,你接了一杯,这杯水就流过去了,你无法对着水龙头喊:“嘿,把刚才流过的第 5 滴水再给我流一遍。”
理想情况:管道直连
如果是普通的上传(比如上传一个 5MB 的头像),逻辑上是不需要临时文件的。
- 左手拿着网络流的入口(
InputStream)。 - 右手拿着最终存储的出口(比如阿里云 OSS 的 SDK,或者本地
FileOutputStream)。 - 动作:一边读,一边写。读一点,写一点。
结论:在普通上传场景下,生成临时文件通常是框架(如 Spring Boot/Tomcat)为了防止内存溢出而做的“缓冲保护”,但在代码逻辑理论上,我们可以不落盘,直接透传。
二、 分片上传:为什么必须要有“临时文件”?
一旦需求变成了**“大文件分片上传”**,情况就完全变了。
假设你要上传一个 1GB 的视频,为了防止网络中断,你决定把它切成 100 片,每片 10MB,一片片传。
这时候,你的代码逻辑通常是这样的:
- 拿到这个 1GB 的大文件。
- 找到第 0~10MB 的数据,切下来,发走。
- 跳到第 10MB~20MB 的数据,切下来,发走。
- …
问题来了:流(Stream)无法“跳跃”
前面说了,前端传过来的 MultipartFile 本质是个流。
流是不能跳的!你不能对流说:“直接跳到第 500MB 的位置读取数据”。你必须把前 499MB 的水全部接出来倒掉,才能见到第 500MB 的水。
这就导致你无法高效地对一个“流”进行切片处理。
救世主:随机访问(Random Access)
为了能随意切片,我们需要一种能力叫 随机访问。
在 Java 中,实现这个能力的类叫 RandomAccessFile。它有一个神技 seek(offset)——也就是“空降”。它可以直接空降到文件的任意位置开始读取,不需要遍历前面的数据。
但是(关键点来了):
RandomAccessFile 有一个物理限制:它必须操作一个真实存在于硬盘上的文件。 它不能操作内存里的流,也不能操作网络上的流。
于是,临时文件诞生了
为了使用“空降切片”的神技,你的代码逻辑被迫变成了这样:
- 先落盘:无论前端传来的是什么流,先把它完整地写到服务器硬盘上,生成一个
.tmp文件。(这一步把“流”变成了“实体”)。 - 后切片:用
RandomAccessFile打开这个实体文件。 - 随意切:这时候你就可以随意指挥了——“去,把第 800MB 到 805MB 的数据读出来发走”。
结论:分片上传必须要有临时文件,因为只有落地的实体文件才支持高效的“随机切取”操作。








