
简介这是一份基于 Java 与 MySQL 的通讯录管理系统课程设计完整项目主要面向计算机专业学生、Java 初学者以及需要完成课设或实训报告的人群。整个资源压缩包共包含 51 个文件大小仅为 3.64MB涵盖 6 个 Java 源文件、30 个 class 编译文件、6 个 XML 工程配置、3 个 CSV 示例数据、1 个 MySQL 驱动 JAR 包和 Word 版实验报告。包内目录划分清晰既有可直接导入开发环境的源码与依赖配置也有编译输出和数据库数据样例能够完整支撑从环境搭建、编码实现到功能测试的整个流程。目前该资源已有 573 人学习下载。学习这份项目可以掌握 Swing 界面开发、JDBC 数据库连接、通讯录的增删改查操作以及 CSV 数据的导入导出方法配套实验报告还梳理了数据库表结构设计和系统实现思路适合作为课程设计模板、答辩讲解或 Java 综合练手项目。1. AddressBook.zip 不只是通讯录压缩包这么简单把AddressBook.zip拆开看它是通讯录数据与 zip 容器两个问题的叠加。在真实环境里它可能是手机导出的 vCard 备份、CRM 系统的联系人导出档也可能是某个离职员工留下的客户资料包。拿到手有人双击解压却发现中文乱码有人输入口令死活不对有人解压完面对一堆 .vcf 不知道下一步怎么导入系统。这里顺着完整链路往下走解压前怎么摸清 zip 包元数据、vCard 到 CSV 的字段映射怎么做、zip 密码恢复和损坏修复的参数怎么选以及最后批量导入时怎么验证结果不出错。适合要做通讯录迁移、数据清洗或系统对接的开发和运维人员也让第一次拿到这种包的初级工程师能顺着步骤走通。2. 解压前的元数据检查用 7-Zip 和 zipfile 看清包内结构2.1 7z l 先看再解避免解压后才发现问题拿到 AddressBook.zip 不建议直接用鼠标双击解压到当前目录。用 7-Zip 的命令行工具先做一次透视能看到包内文件的全貌7z l AddressBook.zip输出里包含每个文件项的完整路径、修改时间、原始大小、压缩后大小和 CRC 校验值。对这份输出要特别注意两件事一是路径层级很多通讯录导出包在压缩时没做路径清理解压后会出现contacts/2024/2024-11-08/export/contacts.vcf这类嵌套结构二是文件数量如果包里有几百个 vcf 文件后续解析就要写成批量脚本而不是单文件处理。确认结构之后正式解压7z x AddressBook.zip -o./ab_export -y-o指定输出目录注意-o后面不能有空格7z x默认保留包内目录结构-y表示遇到重名文件自动覆盖。这里我一般不用7z e因为e会把所有文件平铺到一个目录里多个子目录下的同名文件会被互相覆盖通讯录分组信息也会随之丢失。2.2 Python zipfile 模块不落盘读取包内容和元数据在自动化脚本或 CI 流程里先解压再读取不是一个好习惯。用 Python 标准库 zipfile 在内存里完成检查更干净import zipfile with zipfile.ZipFile(AddressBook.zip) as zf: for info in zf.infolist(): print(f{info.filename}\t{info.file_size}\tCRC{info.CRC:08x})infolist()返回的是每个文件条目的 ZipInfo 对象包含文件名、压缩前后大小、CRC、时间戳等字段。这段代码的意义在于解压任何数据之前就能发现三个常见问题包内是否有非通讯录文件混入、是否有异常大的条目比如联系人照片被打包进去、文件名是否在控制台显示为乱码。zipfile 还能直接按文件名读取压缩条目内容完全不必落地到磁盘import zipfile with zipfile.ZipFile(AddressBook.zip) as zf: with zf.open(contacts/export/contacts.vcf) as f: content f.read().decode(utf-8-sig)zf.open()返回一个类似文件对象的实例read()是一次性读入全部字节。对 vCard 这类文本格式足够用了如果 AddressBook.zip 里打包了带照片的联系人图片文件在几十 KB 到几 MB 之间这时更稳妥的做法是zf.open()配合f.read(65536)分块读取避免单次分配过大内存。表格zipfile 核心方法适用边界方法作用适用场景namelist()返回全部文件名列表快速扫描包内有哪些条目infolist()返回 ZipInfo 对象列表需要大小、CRC、时间戳时read(name)按名一次性读取全部字节小文本文件、快速验证open(name)按名返回文件对象vCard、图片等逐块处理extractall(path)解压全部到指定目录已确认安全后的落地动作2.3 中文文件名的编码还原cp437 回退与 GBK 解码Windows 自带压缩工具和一些老版本压缩软件生成 zip 时文件名用 GBK 编码但没有在 zip 头里标注 UTF-8 标志位。Python zipfile 对这类文件默认按 CP437 字符集解码直接打印就是乱码。先写个小脚本确认当前 zip 文件用的是哪种编码import zipfile with zipfile.ZipFile(AddressBook.zip) as zf: for name in zf.namelist(): print(repr(name))如果输出中出现\xd5\xc5\xce\xb0.vcf这样的字符序列说明原始编码是 GBK。还原文件名要分两步先用 cp437 把它还原成压缩时写入的原始字节再按 GBK 解码raw_bytes name.encode(cp437) real_name raw_bytes.decode(gbk) print(real_name) # 张伟.vcf提示这个技巧同样适用于解压后的文件内容。vCard 文件头没有强制编码声明内容乱码时先用同样的 cp437→GBK 还原思路定位问题。这个编码细节在通讯录场景里几乎是必踩的坑中文姓名是通讯录最核心的数据项文件名和内容双重乱码会让整个导入流程直接报废。3. AddressBook 数据解析vCard 转 CSV 的字段映射与编码清洗3.1 三种通讯录存储格式怎么识别解压完成后面对.vcf、.csv、.json三种常见格式第一步是识别而不是无脑解析。表格通讯录数据格式速查格式扩展名典型来源结构化程度vCard.vcfiOS/Android 通讯录导出块结构字段有序CSV.csv企业 CRM 导出表格型字段顺序取决于模板JSON.jsonAPI 导出树结构键值对自由vCard 是最常见也最容易解析出错的一种。它不是一行一个字段的扁平结构而是由BEGIN:VCARD与END:VCARD包裹的多行块。每个属性由参数:值构成BEGIN:VCARD VERSION:3.0 FN:张伟 N:张;伟;;; TEL;TYPECELL:86 13800138000 EMAIL;TYPEWORK:zhangweiexample.com END:VCARD注意TEL行里的TYPECELL是电话类型标记EMAIL行里的TYPEWORK表示工作邮箱。直接按:做 split 的粗糙解析会丢掉这些元数据后续按手机号/座机/工作邮箱/个人邮箱分列的导入需求就会落空。3.2 用 vobject 把 vCard 解析成结构化数据解析 vCard 不推荐手写正则因为 2.1、3.0、4.0 三个版本的字段写法各有差异数据量大时正则很容易崩。用 vobject 这个 Python 库可以屏蔽掉大部分版本差异import csv from vobject import readComponents def vcf_to_csv(vcf_path, csv_path): records [] with open(vcf_path, r, encodingutf-8-sig) as f: content f.read() for vcard in readComponents(content): name str(vcard.fn.value) if hasattr(vcard, fn) else tels [] if hasattr(vcard, contents) and tel in vcard.contents: for tel in vcard.contents[tel]: tels.append(str(tel.value)) emails [] if hasattr(vcard, contents) and email in vcard.contents: for email in vcard.contents[email]: emails.append(str(email.value)) records.append([name, ;.join(tels), ;.join(emails)]) with open(csv_path, w, encodingutf-8-sig, newline) as f: writer csv.writer(f) writer.writerow([姓名, 电话, 邮箱]) writer.writerows(records) vcf_to_csv(contacts.vcf, contacts.csv)readComponents返回一个生成器逐个 yield 文档中的联系人对象。用hasattr(vcard, fn)判断联系人是否有姓名属性避免拿到只有电话没有姓名的残缺记录时报 AttributeError。tel in vcard.contents的写法比直接访问vcard.tel更安全因为单个联系人有多个电话号码时vcard.tel只暴露第一条contents字典里存的才是全部条目。多个电话用;合并进同一格是为了保持 CSV 的行数与联系人一一对应。如果目标导入系统只接受一个电话字段这种合并方式最不容易丢数据。3.3 中文乱码检测与转码chardet 加置信度判断vCard 文件内容是通讯录解析的另一个重灾区。iOS 导出的 vcf 通常是 UTF-8但 Windows 上 Outlook 通讯录导出、国内不少 CRM 系统导出的 vcf 却用 GBK/GB2312 编码。脚本写死encodingutf-8会在读取阶段直接抛异常或者更糟——读进来了但内容全是乱码。处理这类问题我习惯先用 chardet 检测编码再根据置信度决定怎么解码import chardet def read_text_smart(filepath): with open(filepath, rb) as f: raw f.read(4096) result chardet.detect(raw) print(f编码: {result[encoding]}, 置信度: {result[confidence]}) if result[confidence] 0.7: return raw.decode(result[encoding]) return raw.decode(utf-8, errorsreplace)只读前 4096 字节做检测是因为编码判断依赖的是字节分布特征文件头部的样本量足够让 chardet 给出可靠结论。置信度阈值设在 0.7 是我的习惯——低于这个值说明文件可能经过多次转码或者混入了其他编码的字节自动解码有风险宁可打日志让下游人工确认。这里有个容易忽略的细节UTF-8 编码的文件常带 BOM 头\xef\xbb\xbf如果检测结果显示UTF-8-SIG却用utf-8去解BOM 会作为不可见字符留在第一条记录的姓名前面导入系统后肉眼很难发现但会导致按姓名去重失败。所以 3.2 节代码里读 vcf 时用utf-8-sig就是为了把 BOM 干净地剥掉。4. zip 密码恢复与 CRC 损坏修复工具参数与操作顺序4.1 先把加密类型分清楚ZipCrypto 和 AES-256 难度完全不同遇到带密码的 AddressBook.zip第一步不是急着破解而是判断加密算法。用 7-Zip 打开文件时加密方式一栏会标出ZipCrypto或AES-256。这两种算法在暴力破解时的计算量不在一个数量级。表格常见 zip 密码恢复工具能力对比工具ZipCryptoAES-256GPU 加速适用场景fcrackzip支持不支持否快速测试弱口令、短密码John the Ripper支持支持是字典加规则、混合攻击hashcat支持支持是GPU 暴力与掩码攻击图形界面类工具支持部分支持部分不熟悉命令行的临时场景ZipCrypto 算法设计较弱即使密码较长在 GPU 环境下也能在合理时间内跑完AES-256 则没有捷径只能靠密码本身的强度。所以拿到加密包先看算法如果是 AES-256优先考虑找回密码而不是暴力破解。4.2 fcrackzip 与 hashcat 的实操命令假设这个包确定是 ZipCrypto密码是 4 到 8 位纯数字先用 fcrackzip 做暴力试探fcrackzip -u -b -l 4-8 -p 0 AddressBook.zip-u表示对每个候选密码做实际解压并校验 CRC-b进入暴力模式-l 4-8限定密码长度-p 0从数字 0 开始尝试。这里必须加-u不加时 fcrackzip 只验证 zip 头信息的指纹有可能报出假密码加-u才做真正的解密尝试结果可靠但速度会慢一些。如果手头有一份行业常见的密码字典先跑字典模式通常比暴力模式快一个数量级fcrackzip -u -D -p passwords.txt AddressBook.zip-D切换到字典模式-p后接字典文件路径。通讯录备份的密码往往来自企业安全策略比如姓名缩写工号这类组合好的字典能直接命中。字典跑空之后上 GPU 掩码攻击。先把 zip 的 hash 提取出来再交给 hashcatzip2john AddressBook.zip ab_hash.txt hashcat -m 17225 ab_hash.txt -a 3 ?u?l?l?l?d?d?d?d-m 17225对应当前 ZipCrypto Master Key 攻击模块-a 3是掩码攻击?u表示大写字母?l小写字母?d数字。这个掩码假设密码是大写字母开头 3 个小写字母 4 位数字的 8 位密码是一种常见的企业默认密码规则。跑掩码前先确认密码规律至关重要一个合理的掩码可以把暴力破解的天数缩短到小时。注意如果是 7-Zip 创建的 AES-256 加密包hash 要用 7z2john 提取hashcat 的模块编号对应-m 11600。用-m 17225跑 7z 的 hash 只会得到无用的输出。4.3 error read zip archive 与 CRC failed 的处理顺序解压时报error read zip archive或CRC failed是另一个高频问题。这两个报错含义不同前者指 zip 文件结构层面损坏多为下载中断、拷贝不完整导致中央目录缺失后者表示压缩数据区有字节损坏或密码不对。处理顺序不能乱。先用完整性测试排除密码因素7z t AddressBook.zip -pYOUR_PASSWORD7z t是完整性测试模式带密码逐条校验所有文件条目。输出中Everything is Ok表示数据完好如果列出某个文件名并伴随CRC Failed说明该文件的数据区间确实出了问题。对结构损坏的 zip可以用zip -F尝试重建中央目录zip -F AddressBook.zip --out AddressBook_fixed.zip-F模式下 zip 工具会扫描整个文件尝试重建索引。它救不了压缩数据本身损坏的文件但对中央目录缺失但数据区完整的场景效果显著。修复后务必再用7z t做一次完整性测试确认逐条文件都通过校验之后再进入解压环节。如果-F也无法重建用7z e把还能解的文件全部抽出。这个方案虽然笨但面对高价值的通讯录历史数据每抢回一条记录都值得。5. AddressBook 批量导入前的校验与三个验证维度5.1 解压与校验用一条命令完成批量导入之前先做一遍解压结果校验省得导入系统后才发现中间文件已经损坏7z x AddressBook.zip -o./ab_export -y 7z t AddressBook.zip7z x完成解压7z t对压缩包做整体完整性校验。解压出的文件数量与7z l里看到的条目数不一致时说明有文件在解压中被跳过最常见的原因是文件名编码冲突或磁盘空间不足先解决这两个问题再继续。5.2 批量导入字段映射的脚本骨架企业通讯录导入系统飞书、钉钉、Exchange 或自研后台通常都接受 CSV但字段名各家有各家的叫法。从 vCard 解析出的通用 CSV往往和系统模板对不上import csv FIELD_MAPPING { 手机号: 电话, 姓名: 姓名, 公司邮箱: 邮箱, } with open(contacts.csv, r, encodingutf-8-sig) as f: reader csv.DictReader(f) with open(import_ready.csv, w, encodingutf-8-sig, newline) as out: writer csv.DictWriter(out, fieldnameslist(FIELD_MAPPING.keys())) writer.writeheader() for row in reader: mapped {dest: row.get(src, ) for dest, src in FIELD_MAPPING.items()} writer.writerow(mapped)FIELD_MAPPING字典的键是目标系统的字段名值是通用 CSV 的字段名。实现字段重命名的核心是{dest: row.get(src, )}这一句get加默认空字符串可以防止源 CSV 缺列时抛 KeyError。映射完的文件直接就是目标系统的导入模板格式省掉了导出、手动改表头、再导入的中间步骤。5.3 导入后抽样验证的三个维度批量导入完成后目标系统提示的导入成功 N 条不能全信。通讯录的准确性取决于电话和邮箱两个字段我习惯做三个维度的抽样核对。一是数量对比数一下源 vCard 里 TEL 字段的实际条数和导入系统的联系人记录数做比对grep -c ^TEL contacts.vcf二是格式检查抽样 20 条确认国内手机号是否保留了86前缀、座机号码是否带区号、有没有空姓名记录。三是字段错位检查拿源 vCard 里的前 5 个联系人姓名去目标系统搜索逐个确认电话和邮箱能对上。三个维度核对完这套解压、解析、导入、验证的链路才真正走完。下次再遇到带编码问题和密码问题的 AddressBook.zip先7z t验包再用 cp437→GBK 还原文件名能避开一大半的坑。本文还有配套的精品资源点击获取