开发者

Android使用Zip4j实现加密压缩功能

目录
  • 一、为什么选择Zip4j?
  • 二、环境配置
    • 1. 添加依赖
    • 2. 权限配置
  • 三、核心功能实现
    • 1. 基础加密压缩工具类
    • 2. 带进度回调的高级压缩
    • 3. 多文件选择性加密压缩
  • 四、android存储适配
    • 五、完整使用示例
      • 1. 压缩照片并加密
      • 2. 带进度条的大文件压缩
      • 3. 解压加密文件
    • 六、高级配置选项
      • 1. 自定义压缩参数
      • 2. 分卷压缩(适合大文件)
    • 七、常见问题解决方案
      • 1. 密码强度问题
      • 2. 存储权限问题
      • 3. 内存优化
    • 八、性能优化建议
      • 九、总结与最佳实践
        • 关键点总结
        • 推荐实践

      一、为什么选择Zip4j?

      Zip4j是一个功能强大的Java库,专为处理加密ZIP文件而设计,相比Android原生Zip工具具有显著优势:

      特性Android原生ZipZip4j
      加密支持AES和标准ZIP加密
      密码保护不支持支持
      大文件处理有限优秀
      压缩级别控制9级可调
      文件覆盖处理基础高级选项
      进度回调支持

      二、环境配置

      1. 添加依赖

      在模块级build.gradle.kts中添加:

      dependencies {
          implementation("net.lingala.zip4j:zip4j:2.11.5")
          // 最新版本请查看:https://github.com/srikanth-lingala/zip4j
      }
      

      2. 权限配置

      AndroidManifest.XML中添加存储权限:

      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                       android:maxSdkVersion="28"/> <!-- Android 9及以下需要 -->
      
      <!-- 对于Android 10+,使用Scoped Storage -->
      <application
          android:requestLegacyExternalStorage="true"
          ... >
      </application>
      

      三、核心功能实现

      1. 基础加密压缩工具类

      import android.content.Context
      import net.lingala.zip4j.ZipFile
      import net.lingala.zip4j.model.ZipParameters
      import net.lingala.zip4j.model.enums.CompressionLevel
      import net.lingala.zip4j.model.enums.CompressionMethod
      import net.lingala.zip4j.model.enums.EncryptionMethod
      import java.io.File
      
      class ZipEncryptor(private val context: Context) {
      
          /**
           * 加密压缩文件或文件夹
           * @param sourcePath 源路径(文件或文件夹)
           * @param zipFilePath 生成的ZIP文件路径
           * @param password ZUtrOfQbB加密密码
           * @param encryptionMethod 加密方法(默认AES-256)
           */
          fun encryptAndCompress(
              sourcePath: String,
              zipFilePath: String,
              password: String,
              encryptionMethod: EncryptionMethod = EncryptionMethod.AES
          ) {
              val sourceFile = File(sourcePath)
              val zipFile = ZipFile(zipFilePath, password.toCharArray())
              
              val parameters = ZipParameters().apply {
                  compressionMethod = CompressionMethod.DEFLATE
                  compressionLevel = CompressionLevel.NORMAL
                  isEncryptFiles = true
                  this.encryptionMethod = encryptionMethod
              }
      
              when {
                  sourceFile.isFile -> zipFile.addFile(sourceFile, parameters)
                  sourceFile.isDirectory -> zipFile.addFolder(sourceFile, parameters)
                  else -> throw IllegalArgumentException("无效的源路径: $sourcePath")
              }
          }
      
          /**
           * 安全解压加密ZIP文件
           * @param zipFilePath ZIP文件路径
           * @param destDirectory 解压目标目录
           * @param password 解密密码
           */
          fun decryptAndExtract(
              zipFilePath: String,
              destDirectory: String,
              password: String
          ) {
              val zipFile = ZipFile(zipFiwww.devze.comlePath, password.toCharArray())
              zipFile.extractAll(destDirectory)
          }
      }
      

      2. 带进度回调的高级压缩

      import net.lingala.zip4j.progress.ProgressMonitor
      
      class AdvancedzipEncryptor(context: Context) : ZipEncryptor(context) {
      
          /**
           * 带进度回调的加密压缩
           * @param progressCallback 进度回调 (当前字节数, 总字节数)
           */
          fun encryptWithProgress(
              sourcePath: String,
              zipFilePath: String,
              password: String,
              progressCallbjsack: (Long, Long) -> Unit
          ) {
              val zipFile = ZipFile(zipFilePath, password.toCharArray())
              val parameters = ZipParameters().apply {
                  isEncryptFiles = true
                  encryptionMethod = EncryptionMethod.AES
              }
              
              val sourceFile = File(sourcePath)
              
              // 启动进度监控线程
              Thread {
                  var lastProgress = 0L
                  while (true) {
                      val progress = zipFile.progressMonitor
                      if (progress.state == ProgressMonitor.State.BUSY) {
                          if (progress.workCompleted > lastProgress) {
                              progressCallback(progress.workCompleted, progress.totalWork)
                              lastProgress = progress.workCompleted
                          }
                      } else if (progress.state == ProgressMonitor.State.READY) {
                          break
                      }
                      Thread.sleep(100)
                  }
              }.start()
      
              // 执行压缩操作
              when {
                  sourceFile.isFile -> zipFile.addFile(sourceFile, parameters)
                  sourceFile.isDirectory -> zipFile.addFolder(sourceFile, parameters)
              }
          }
      }
      

      3. 多文件选择性加密压缩

      fun encryptSelectedFiles(
          filePaths: List<String>,
          zipFilePath: String,
          password: String
      ) {
          val zipFile = ZipFile(zipFilePath, password.toCharArray())
          val parameters = ZipParameters().apply {
              isEncryptFiles = true
              encryptionMethod = EncryptionMethod.AES
          }
          
          val files = filePaths.map { File(it) }
          zipFile.addFiles(files, parameters)
      }
      

      四、Android存储适配

      针对不同Android版本处理存储权限:

      import android.os.Build
      import android.os.Environment
      import androidx.core.content.ContextCompat
      
      fun getSafeStoragePath(context: Context, folderName: String): File {
          return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
              // Android 10+ 使用应用专属目录
              File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), folderName)
          } else {
              // Android 9及以下使用传统存储
              File(Environment.getExternalStorageDirectory(), "Documents/$folderName")
          }.apply { mkdirs() }
      }
      

      五、完整使用示例

      1. 压缩照片并加密

      fun compressPhotos(context: Context) {
          val zipUtil = ZipEncryptor(context)
          val photosDir = getSafeStoragePath(context, "Photos")
          val zipPath = File(getSafeStoragePath(context, "Archives"), "photos_encrypted.zip").absolutePath
          
          try {
              zipUtil.encryptAndCompress(
                  sourcePath = photosDir.absolutePath,
                  zipFilePath = zipPath,
                  password = "Secure@Password123!",
                  encryptionMethod = EncryptionMethod.AES
              )
              Toast.makeText(context, "照片加密压缩完成", Toast.LENGTH_SHORT).show()
          } catch (e: Exception) {
              Log.e("ZipError", "压缩失败: ${e.message}")
              Toast.makeText(context, "压缩失败: ${e.message}", Toast.LENGTH_LONG).show()
          }
      }
      

      2. 带进度条的大文件压缩

      fun compressLargeFileWithProgress(context: Context, progressBar: ProgressBar) {
          val advancedZip = AdvancedZipEncryptor(context)
          val largeFilePath = getSafeStoragePath(context, "Videos").resolve("large_video.mp4").absolutePath
          val zipPath = File(getSafeStoragePath(context, "Archives"), "video_encrypted.zip").absolutePath
          
          advancedZip.encryptWithProgress(
              sourcePath = largeFilePath,
              zipFilePath = zipPath,
              password = "StrongPassword!456"
          ) { current, total ->
              // 更新UI进度
              runOnUiThread {
                  progressBar.max = total.toInt()
                  progressBar.progress = current.toInt()
              }
          }
      }
      

      3. 解压加密文件

      fun extractEncryptedZip(context: Context) {
          val zipUtil = ZipEncryptor(context)
          val zipPath = File(getSafeStoragePath(context, "Archives"), "photos_encrypted.zip").absolutePath
          val extractDir = getSafeStoragePath(context, "ExtractedPhotos")
          
          try {
              zipUtil.decryptAndExtract(
                  zipFilePath = zipPath,
                  destDirectory = extractDir.absolutePath,
                  password = "Secure@Password123!"
              )
              Toast.makeText(context, "文件解压成功", Toast.LENGTH_SHORT).show()
          } catch (e: Exception) {
              Log.e("ZipError", "解压失败: ${e.message}")
              Toast.makeText(context, "解压失败: 密码错误或文件损坏", Toast.LENGTH_LONG).show()
          }
      }
      

      六、高级配置选项

      1. 自定义压缩参数

      fun getCustomZipParameters(): ZipParameters {
          return ZipParameters().apply {
              compressionMethod = CompressionMethod.DEFLATE
              compressionLevel = CompressionLevel.MAXIMUM // 最高压缩率
              isEncryptFiles = true
              encryptionMethod = EncryptionMethod.AES
              aesKeyStrength = AesKeyStrength.KEY_STRENGTH_256 // 256位AES加密
              
              // 文件覆盖选项
              fileExistsInZipMode = FileExistsInZipMode.OVERWRITE
              
              // 设置文件注释
              fileComment = "Created on ${SimpleDateFormat("yyyy-MM-dd").format(Date())}"
              
              // 设置解压后文件属性(Unix系统)
              unixFileAttributes = 644
          }
      }
      

      2. 分卷压缩(适合大文件)

      fun splitZipCreation(context: Context) {
          val sourceFile = getSafeStoragePath(context, "Database").resolve("backup.db")
          val zipPath = File(getSafeStoragePath(context, "Archives"), "db_backup.zip").absolutePath
          
          val zipFile = ZipFile(zipPath, "backupPassword123!".toCharArray())
          val parameters = ZipParameters().apply {
              isEncryptFiles = true
              encryptionMethod = EncryptionMethod.AES
          }
          
          // 设置分卷大小(100MB)
          zipFile.isSplitArchive = true
          zipFile.splitLength = 100 * 1024 * 1024 // 100MB
          
          zipFile.addFile(sourceFile, parameters)
      }
      

      七、常见问题解决方案

      1. 密码强度问题

      错误信息net.lingala.zip4j.exception.ZipException: Password is too weak

      解决方案

      fun isStrongPassword(password: String): Boolean {
          // 至少8位,包含大小写字母、数字和特殊字符
          val pattern = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$".toRegex()
          return pattern.matches(password)
      }
      

      2. 存储权限问题

      错误信息java.io.FileNotFoundException: ... (Permission denied)

      解决方案

      // 在Activity中请求权限
      private fun requestStoragePermission() {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
              ActivityCompat.requestPermissions(
                  this,
                  arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                  STORAGE_PERMISSION_CODE
              )
          } else {
              // Android 10+ 不需要请求存储权限
              startCompression()
          }
      }
      
      override fun onRequestPermissionsResult(
          requestCode: Int,
          permissions: Array<out String>,
          grantResults: IntArray
      ) {
          if (requestCode == STORAGE_PERMISSION_CODE && 
              grantResults.isNotEmpty() && 
              grantResults[0] == PackageManager.PERMISSION_GRANTED) {
              startCompression()
          } else {
              Toast.makeText(this, "需要存储权限才能执行此操作", Toast.LENGTH_LONG).show()
          }
      }
      

      3. 内存优化

      处理大文件时使用流式压缩避免OOM:

      fun streamCompression(sourceFile: File, zipPath: String, password: String) {
          val zipFile = ZipFile(zipPath, password.toCharArray())
          val parameters = ZipParameters().apply {
              isEncryptFiles = true
              encryptionMethod = EncryptionMethod.AES
          }
          
          FileInputStream(sourceFile).use { fis ->
              zipFile.addStream(fis, parameters)
          }
      }
      

      八、性能优化建议

      1.压缩级别选择

      • CompressionLevel.FASTEST:速度最快,压缩率低
      • CompressionLevel.NORMAL:平衡模式(默认)
      • CompressionLevel.MAXIMUM:最高压缩率,速度慢

      2.多线程压缩(Zip4j 2.x+):

      zipFile.setRunInThread(true) // 启用后台线程压缩
      

      3.文件筛选(避免压缩不必要文件):

      parameters.fileExclusionFilters = listOf(
          FileFilter { file -> file.name.endsWith(".tmp") },
          FileFilter { file -> file.name.startsWith("temp_") }
      )
      

      九、总结与最佳实践

      关键点总结

      • 安全优先:始终使用AES-256加密保护敏感数据
      • 密码android策略:强制用户使用强密码(8+字符,混合类型)
      • 存储适配:正确处理Android不同版本的存储权限
      • 进度反馈:对大文件操作提供进度显示
      • 错误处理:优雅处理密码错误、文件损坏等情况
      • 资源管理:及时关闭文件流,避免资源泄漏

      推荐实践

      fun safeZipOperation(context: Context) {
          try {
              // 1. 验证源文件存在
              val sourceFile = File(sourcePath)
              if (!sourceFile.exists()) throw FileNotFoundException("源文件不存在")
              
       编程客栈       // 2. 验证目标路径可写
              val zipFile = File(zipPath)
              if (zipFile.exists() && !zipFile.canWrite()) throw IOException("目标文件不可写")
              
              // 3. 验证密码强度
              if (!isStrongPassword(password)) throw IllegalArgumentException("密码强度不足")
              
              // 4. 执行压缩
              val zipUtil = ZipEncryptor(context)
              zipUtil.encryptAndCompress(sourcePath, zipPath, password)
              
              // 5. 验证结果
              if (!zipFile.exists() || zipFile.length() == 0L) {
                  throw IOException("压缩文件创建失败")
              }
              
              // 6. 清理临时文件(如果需要)
              // ...
              
          } catch (e: Exception) {
              Log.e("ZipOperation", "操作失败", e)
              // 通知用户并提供解决方案
          }
      }
      

      Zip4j为Android提供了强大的加密压缩能力,合理使用可以显著提升应用的数据安全性。建议在实际项目中根据具体需求选择合适的压缩参数和加密级别,并在关键操作中添加适当的日志记录和异常处理。

      到此这篇关于Android使用Zip4j实现加密压缩功能的文章就介绍到这了,更多相关Android Zip4j加密压缩内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜