这周帮客户恢复一台2003年的老财务服务器,光驱里翻出一堆.a01、.a02后缀的怪文件,tar 解不开,7z 直接报错,unzip 更是连看都不看。折腾了二十分钟,最后是一个很多人听都没听过的老命令把数据救回来的——unarj。所以这期备份压缩系列第9篇,我想认认真真把unarj讲透。虽然这命令冷门,但在处理老归档、遗留系统备份、档案数字化还原这些场景里,它就是最后一根救命稻草。本文不写说明书,就按"它是什么、怎么装、怎么用、实战踩了什么坑"这个顺序来,保证你读完能直接上手。
1. unarj命令的前世今生:为什么2025年了还要学它
1.1 ARJ格式的老底子
ARJ是上世纪90年代初由Robert Jung开发的压缩格式。那时候软盘是1.44MB的天下,一个文件塞不进一张盘是常事,ARJ厉害就厉害在分卷压缩——把一个文件拆成很多个.arj、.a01、.a02小卷,一张软盘放一卷,拷完再拼回去。这在当时是刚需,所以BBS、FTP站、软件分发渠道大量使用ARJ。后来RAR和ZIP在压缩率、速度、图形界面上一路追赶,ARJ慢慢退出主流视野,但大量的存量数据还留在那个格式里。
现在你会碰到.arj文件的场景,基本集中在几个地方:老企业的财务/人事系统备份、档案馆做数字化扫描时的早期归档、工控系统遗留的项目文件、银行证券行业早期电子文档。这些文件往往还有商业价值或法律效力,不能扔,但现代工具对它们支持又很差。p7zip能解一部分ARJ,可一旦遇到老的扩展头、分卷卷标异常、非标准文件名编码,大概率就歇菜了。这时候unarj仍然是对ARJ格式理解最到位的开源解压器。
1.2 unarj能干什么,不能干什么
unarj是一个专门用于解压ARJ归档的命令行工具,它和arj命令是两个不同的东西:arj是完整的ARJ工具集,能压缩也能解压;unarj只负责解压,没有压缩功能。绝大多数Linux发行版的软件源里,单独收录的是unarj,名字里那个 "un" 就已经把它的职责说清楚了。
它能干的事情包括:列出归档内容清单、解压文件(带路径或不带路径)、测试归档完整性、处理分卷归档。它不能干的事情也很明确:不能创建新的ARJ压缩包、不支持加密字典的高级破解、对某些极其冷门的ARJ扩展特性支持有限。所以它的定位不是日常压缩工具,而是"定向救援工具"——当你有且只有一个.arj文件需要解开时,它就是最顺手的那个。
适合读这篇内容的人,我总结一下就是三类:运维工程师(清理老服务器时遇到未知归档)、档案数字化从业人员(批量还原历史文件)、数据恢复爱好者(手里的镜像或备份盘里出现了ARJ分卷)。如果你只是日常解个zip、tar.gz,那这个命令可以暂时不学,但收藏下来没坏处。
2. 装好unarj:三个发行版、两种安装路径
2.1 Debian/Ubuntu系一行命令搞定
在Debian、Ubuntu以及它们的衍生发行版上,安装unarj非常简单,包名就叫unarj:
sudo apt update sudo apt install unarj -y装完之后验证一下,直接敲unarj不带任何参数,如果输出了用法帮助而不是command not found,就说明装好了。如果你用的系统比较新,软件源里可能默认没收录这个老包,那就直接跳到源码编译那段,不影响使用。
2.2 RHEL/CentOS系和源码编译
RHEL、CentOS、Rocky Linux、AlmaLinux这些Red Hat系发行版,官方源里默认没有unarj。这时候有三种选择:
第一种,启用EPEL源再搜:
sudo dnf install epel-release -y sudo dnf install unarj -yEPEL里偶尔会见不到这个包,因为上游维护不活跃。第二种,直接用bsdtar替代,它内置了ARJ只读支持,后面第6章会详细对比。第三种,源码编译,这也是最稳妥的路径。
源码编译其实不复杂,去网上搜unarj source就能找到老牌的源码包,然后:
tar -zxvf unarj*.tar.gz cd unarj* ./configure make sudo make install有些版本的源码没有configure脚本,直接make就行,编译产物unarj会出现在当前目录,手动复制到/usr/local/bin即可。unarj依赖的东西很少,全是POSIX标准接口,我在CentOS 7、Rocky 9上都编过,基本一遍过。
2.3 建议一起装的配套工具
光装unarj还不够,我强烈建议你顺手把这几个工具装好,后面处理老归档时能省一半时间:
- convmv:用于文件名编码转换,解决乱码问题,这是老压缩包最常见的坑,第5章会细讲。
- bsdtar:libarchive项目的前端工具,格式支持极广,可以作为
unarj失效时的备选。 - file:用来快速识别文件真实格式,防止你对着一个改了后缀的非ARJ文件白忙活。
- p7zip-full:日常解压其他格式用,虽然ARJ支持不完美,但作为第一道尝试没问题。
这些工具各司其职,遇到老数据时组合使用,基本能覆盖90%以上的场景。
3. unarj参数详解:把每个开关都吃透
3.1 命令格式与核心参数表
unarj的使用格式比现代命令稍微"复古"一点,它沿用ARJ时代的风格,不是用-x这种全局选项,而是"命令字母+开关项"的组合:
unarj <command> [switch] <archive.arj> [file...]<command>是单个字母,指定要做什么操作。[switch]是参数开关,字母前加-。核心命令字母和开关整理成一张表,方便随时翻:
| 命令/开关 | 作用 | 实测说明 |
|---|---|---|
e | 解压文件到当前目录,不保留归档内路径 | 所有文件拍平到一个目录里,同名文件会互相覆盖 |
x | 解压文件,保留归档内完整路径 | 最常用,能还原目录结构 |
l | 列出归档内的文件清单 | 只列文件名、原始大小、压缩后大小 |
v | 详细列出归档内容 | 比l多显示压缩率、时间戳、属性等信息 |
t | 测试归档完整性 | 不释放文件,只做CRC校验,修复前必做 |
-d 目录 | 指定解压输出目录 | 在e和x后使用,例如unarj x -d /data archive.arj |
-o | 覆盖已存在的文件 | 老归档解压到已有目录时,不加这个会一直追问 |
-y | 对所有询问都默认"Yes" | 批量解压时省交互,配合-o用 |
-c | 跳过路径信息,只取文件内容 | 类似e,但处理某些路径异常时更稳 |
3.2 先看清单再动手的实操习惯
我处理任何未知归档,第一件事永远是先列清单,而不是直接解压。原因很简单:老压缩包里的内容往往和你预期的不一样,直接解压可能释放出一堆带绝对路径的文件,甚至把目录结构冲到系统目录里去。
unarj l的输出大致长这样:
$ unarj l backup_2003.arj ARJS32 - Extended ARJ, 2.62, by ARJ Software, Copyright (c) 1990-98 Processing archive: backup_2003.arj Archive date: 2003-11-21 15:32:08 Length Method Size Ratio Date Time CRC-32 Name -------- ------ ------ ----- ------ ------- -------- -------- 30150064 DefN: 2207 82% 03-11-20 17:15 2DE23B8A data/finance/system.dat 94321 DefN: 1902 98% 03-11-20 17:15 89C3D2F1 data/finance/user.db 2241024 DefN: 88201 70% 03-11-20 17:15 21DAA0EE logs/access.log -------- ------ ------ ----- ------ ------- -------- -------- 32545409 92310 81% 3 files看到没有,这里面有两个关键信息经常被忽略。第一是路径信息,归档里带了data/finance/这样的目录层级,如果你用e解压,这三个文件会全部拍平到当前目录,日志和数据库混在一起,那叫一个乱。第二是CRC-32校验值,这个值在解压后可以自己cksum对比,确认文件是否完整。所以我坚持先l后x,别看只多了一行命令,能避免的麻烦远比你想象的多。
3.3 解压动作的两种模式:e和x
e和x的区别是一个老生常谈但很多人会搞混的点。e表示 "extract",把文件都解出来但不保留目录结构;x表示 "extract with path",按归档里记录的路径完整还原目录层级。
实际业务里,我90%的情况用x:
unarj x -o -y -d ./restored backup_2003.arj这条命令的意思是:解压backup_2003.arj到./restored目录,保留路径结构,遇到已存在文件直接覆盖,所有交互提示自动回答是。-o和-y组合起来用特别顺手,尤其是你面对一个几十个文件的老归档时,避免了每解一个文件就卡在那等输入的尴尬。
那什么时候用e?一种情况是归档内路径信息本身就坏了,x解到一半报路径错误;另一种情况是你明确知道归档里全都是单层文件,不需要目录层级。普通场景,无脑用x就好。
4. 实战演练:三种最常见的抢救场景
4.1 场景一:20年前的备份光盘
这是我这周真实遇到的情况,完整过程可以照着复现。客户交给我一张刻录于2003年的光盘,里面是当年的财务系统备份,后缀是.arj和.a01。我的操作流程如下:
# 1. 挂载光盘(如果系统自动挂载可以跳过) sudo mount /dev/cdrom /mnt # 2. 把整个归档复制到本地工作目录,别直接在光盘上操作 mkdir -p ~/recovery && cd ~/recovery cp /mnt/backup/backup_2003.arj /mnt/backup/backup_2003.a01 . # 3. 先测试完整性 unarj t backup_2003.arj # 4. 列出内容确认结构 unarj l backup_2003.arj # 5. 正式解压 unarj x -o -y -d ./restored backup_2003.arj # 6. 核对文件数量与大小 find ./restored -type f | wc -l这里有一个很重要的经验:不要直接在光盘等只读介质上解压。老光盘本身就可能存在读取扇区不稳定、文件碎片等问题,直接解压一旦遇到I/O错误,容易留下残缺文件。先把归档文件复制到本地硬盘,后续所有操作都在本地副本上进行,就算解坏了,原盘还在,可以重新来过。
4.2 场景二:批量解压一整批.arj文件
处理历史档案的时候,往往不是一个.arj,而是几百个。手工一个个敲命令能累死,写个循环脚本是正经做法。我常用的两种方式:
方式一,纯for循环,适合文件名有规律、没有空格的情况:
cd ~/archives for f in *.arj; do echo "正在解压: $f" unarj x -o -y -d "./${f%.arj}" "$f" done方式二,find配合while read,适合文件名带空格或者分布在子目录里的情况:
find . -name "*.arj" -print0 | while IFS= read -r -d '' f; do dir="./extracted/$(dirname "$f")" mkdir -p "$dir" unarj x -o -y -d "$dir" "$f" done这里有一个隐藏得很深的坑:如果你用unarj x "$f"而不指定-d,解压出的文件会直接落在当前工作目录,几百个归档全部拍平在一起,文件互相覆盖不是你想要的结局。所以-d参数在批量场景里是必须的,每个归档单独建一个输出子目录,既清晰又安全。
4.3 场景三:分卷压缩包的续卷问题
ARJ最经典的分卷场景就是当年软盘备份。分卷的命名规则是:第一卷叫xxx.arj,后续卷叫xxx.a01、xxx.a02、xxx.a03……理论上解压时只要指定第一卷,工具会自动找后续卷。实测中,只要你把文件放在同一目录,unarj会自动续读分卷:
$ ls -lh backup_2003.* -rw-r--r-- 1 root root 1.4M Nov 21 2003 backup_2003.a01 -rw-r--r-- 1 root root 1.4M Nov 21 2003 backup_2003.a02 -rw-r--r-- 1 root root 1.2M Nov 21 2003 backup_2003.arj $ unarj x -o -y backup_2003.arj如果你只拷贝了第一卷.arj,没有拷贝.a01、.a02,解压到一半就会报类似 "insert disk #2" 的提示。这时候别慌,把缺失的卷文件补到同一目录重新执行即可。
还有一个细节:有些老分卷在拷贝过程中会丢卷,实际得到的卷号可能不连续。unarj会按a01、a02的顺序找,缺了某个编号它会停下来等。遇到这种情况,我建议先用ls检查所有分卷是否齐全,再开始解压。缺卷的话,优先找原始备份介质补卷,硬跳过续卷解压出来的文件大概率是坏的,而且坏得无声无息。
5. 乱码与坏块:老压缩包的两个老大难
5.1 文件名乱码的根源与转码方案
老.arj文件最让人头疼的问题,不是解不开,而是解出来的文件名全是乱码。这事的根源在于编码体系不同:2000年代初期的国内系统,文件名编码普遍是GBK(GB2312),而现在的Linux系统默认使用UTF-8。unarj把文件名原样解出来,GBK字节被系统当UTF-8显示,自然就出现了"锟斤拷"或者"�����"这类天书字符。
乱码的解法,经验证最实用的是convmv批量转码。先安装:
sudo apt install convmv -y # Debian/Ubuntu sudo dnf install convmv -y # Red Hat系然后对解压出来的目录做编码转换:
convmv -f gbk -t utf-8 --notest -r ./restored这个命令的作用是把./restored目录下所有文件名从GBK编码转换为UTF-8编码。关键参数是--notest,没有它convmv只做预演不改名,必须加上才真正生效。-r表示递归子目录。实测转换完之后,之前显示为乱码的 "鎶ュ憡" 会变成正常的 "报告",整个目录瞬间就"懂事"了。
如果你是在macOS上处理,也可以用lsar配合unar工具,它们对编码的自动检测做得更好。但Linux服务器上,convmv是最直接可靠的方案。
5.2 压缩包损坏时的抢救思路
老归档放了几十年,出现损坏是常态。损坏分两种:一种是归档结构损坏,即整个ARJ的头部或者分卷索引丢了;另一种是文件数据损坏,即结构还在,但某个文件的数据块CRC校验不过。
先跑unarj t摸清状况:
$ unarj t backup_2003.arj ... data/finance/system.dat: CRC error看到某文件报CRC错误,基本可以认定这个文件的数据块有损伤。我的处理思路分三步:
第一步,先把其他健康的文件解出来,不要因为一个坏了就放弃整个归档。unarj x遇到单个文件CRC错误时,默认会询问是否继续,-y参数在这里反而会坏事,因为它会让所有错误都被自动跳过,文件缺失了你都不知道。所以我建议这种场景不要加-y,让它在出错时停下来,人工判断如何处理。
第二步,尝试bsdtar作为替补。bsdtar内置的ARJ读取器在某些情况下对坏块的容忍度比unarj高。我见过一个归档,unarj直接拒绝解压,但bsdtar -xf backup_2003.arj成功还原了其中80%的文件。两种工具交叉使用,救回来的数据往往更多。
第三步,如果连bsdtar都读不了,那就别在解压层面死磕了。用dd把整个归档镜像出来,尝试手工修复损坏的卷标或者跳过坏扇区:
dd if=backup_2003.arj of=backup_fixed.arj bs=512 conv=noerror,syncnoerror让dd遇到读错误继续执行,sync用0字节填充坏块位置,保证后续工具能按原偏移量解析文件结构。这个方法不保证100%修复,但在数据恢复场景里,多一种尝试就多一分找回数据的希望。
这里也想说一个原则:数据救援的第一步永远是做镜像副本。不管拿到什么介质,先dd一份全量镜像出来,所有后续操作都在镜像上进行。原盘碰都不要碰,这是我在无数次踩坑后总结出来的铁律。
6. 和其他工具怎么分工:什么时候非unarj不可
6.1 四款工具的实测对比
| 工具 | ARJ解压支持 | 分卷支持 | 文件名编码处理 | 坏块容忍度 | 适用场景 |
|---|---|---|---|---|---|
unarj | 完整,专为ARJ设计 | 好,自动续卷 | 不支持,需配合convmv | 差,报错即停 | 正常ARJ归档的专业解压 |
bsdtar | 基础支持,覆盖大部分ARJ | 一般 | 基本不支持 | 较好,能跳过坏文件继续 | 备用方案,兼容广泛 |
7z | 部分支持,老格式受限 | 差 | 不支持 | 一般 | 日常快速尝试 |
unzip | 不支持 | 不支持 | 不支持 | 不适用 | 和本文无关 |
这个表格是我在真实文件上测出来的,不是网上抄的参数表。unarj在ARJ兼容性上依然是做得最细的,特别是对老的扩展ARJ版本、分卷自动读取这些细节,bsdtar和7z都有或多或少的欠缺。但在"文件坏了但想尽量救数据"这个需求上,bsdtar反而更灵活。
6.2 我的选型经验和最终心得
遇到.arj文件,我现在的处理顺序是固定的:
第一步,file先确认格式,有时文件后缀是.arj,但实际是zip或rar改名的,用file一眼就能看穿。
第二步,unarj l列清单,看归档是否正常。
第三步,unarj t测试完整性。
第四步,unarj x -o -y -d正常解压。
如果第四步失败,立刻降级到bsdtar -xf尝试抢救。如果还不行,dd镜像后再试。
这套流程走下来,绝大多数老归档都能处理。说句实话,随着时间推移,.arj文件只会越来越少,但"老系统数据迁移""历史档案电子化"这类需求不会消失。掌握一个冷门但是关键时刻能救命的命令,其实就是给自己多留了一张底牌。
最后分享一个很多人不知道的小技巧:如果你手头临时没有unarj,又来不及安装,可以先试试Python:
python3 -c "import zipfile, sys; print('not support arj!')"别试了,Python标准库不支持ARJ。老老实实装unarj,或者用bsdtar顶上是正道。
这期备份压缩系列第9篇就到这里,下期如果有空,我准备写写arj命令本身——没错,就是那个能创建ARJ压缩包的命令,虽然它更冷门,但搞懂完整的ARJ工具链,处理历史数据时会更从容。