randomaccessfile多线程读写需手动分片并严格对齐边界:读取时须按行/分隔符对齐避免截断,写入时每个线程独立打开文件、seek到精确offset、写完关闭;合并前需清空目标文件、加分布式锁、校验分片连续性,且前后端分片大小必须字节级一致。

RandomAccessFile 多线程读取必须手动切分文件边界
RandomAccessFile 本身不提供“自动分片”能力,所有线程的 seek() 起始位置和读取长度必须由你精确计算并传入。常见错误是直接用文件总大小除以线程数,再让每个线程读固定字节数——这会破坏行边界(如 CSV/日志)、导致 UTF-8 字节截断、或跳过部分数据。
实操建议:
- 先用
RandomAccessFile.length()获取总字节长度,再按需均分逻辑块(例如每块 10MB),但不直接读满该长度 - 每个线程在定位到起始
seek(startPos)后,优先用readLine()或逐字节扫描找换行符/记录分隔符,确保读到完整行再停止 - 若处理二进制格式(如视频、压缩包),才可严格按字节长度读;此时需保证
startPos + chunkSize ,否则 <code>read()可能阻塞或抛EOFException - 避免多个线程共用同一个
RandomAccessFile实例;每个线程应独立打开、seek、读、关闭
合并时 seek() 写入前必须确保目标文件已存在且为空
用 new RandomAccessFile(target, "rw") 打开一个尚不存在的文件,JVM 会创建它;但如果该文件已存在,"rw" 模式默认不会清空内容,而是从头覆盖——这会导致旧数据残留,尤其当新文件比旧文件短时,尾部脏数据仍在。
实操建议:
- 合并前强制执行
new File(targetPath).createNewFile(),确保文件存在且长度为 0 - 每个分片写入位置必须是
chunkIndex * chunkSize,且服务端要校验chunkIndex从 0 开始、连续、无重复或缺失 - 不要复用同一个
RandomAccessFile实例写多个分片;每个写操作应独立打开 →seek()→write()→close() - 更稳妥的做法是改用
FileChannel:用Files.newByteChannel(Paths.get(target), StandardOpenOption.CREATE, StandardOpenOption.WRITE),再调用position(offset).write(buffer),天然支持并发写不同 offset
前端传分片参数必须走 @RequestParam,别碰原始 input stream
很多开发者试图从 HttpServletRequest.getInputStream() 手动解析 multipart/form-data,结果拿不到 chunkIndex、identifier 等字段,因为这些是表单字段,不是文件内容本身。一旦解析错位,后端就无法判断该把当前 chunk 写到哪个 offset,甚至混淆不同用户的上传任务。
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
实操建议:
- 前端必须用
FormData提交,且显式 append 三个字段:file(Blob)、chunkIndex(数字)、identifier(唯一 ID,如文件名+时间戳的 MD5) - 后端用
@RequestParam("chunkIndex") Integer chunkIndex和@RequestParam("identifier") String identifier接收,而不是自己 parse 流 - 临时分片目录结构设为
/upload/chunks/{identifier}/,避免同名文件覆盖 -
totalChunks仅用于完整性校验,不要靠它触发合并;真正可靠的是:收到chunkIndex == totalChunks - 1且 本地目录下已存在totalChunks个文件
并发写入必须加锁,否则合并结果损坏不可逆
多个请求同时向同一目标文件的不同 offset 写入,看似互不干扰,但操作系统级的 write() 调用在极端情况下仍可能因缓存、磁盘调度等原因导致写入错乱。更危险的是多个请求同时触发合并逻辑——比如两个线程都判断“这是最后一片”,都开始 seek(0) 并重写文件头,结果相互覆盖。
实操建议:
- 对每个
identifier的合并操作加分布式锁,推荐用 Redis 锁(key ="merge_lock:" + identifier),超时设为 5 分钟 - 文件锁(
FileChannel.lock())只在单 JVM 进程内有效,集群部署时不适用 - 合并完成后,立即清空对应临时目录
/upload/chunks/{identifier}/,防止残留分片干扰下次上传 - 合并失败时,保留临时分片并记录错误日志,不要静默删除——否则断点续传将失去依据
真正容易被忽略的是:分片写入时的字节对齐必须和服务端拆分逻辑完全一致。前端按 1MB 切,后端就必须用 1024×1024 计算 offset;差 1 字节,后续所有分片都会偏移,最终文件解不开、打不开、校验失败。这个细节没有日志报错,只能靠人工比对或预埋 offset 校验逻辑来发现。










