Android otg 、U盤中使用zip4j 的ZipOutputStream進行壓縮檔案新增密碼
使用zip4j庫在Android外部儲存 上進行帶密碼的壓縮檔案
最近在做專案的時候接觸到需要在app上對壓縮檔案進行加密,也就是像pc上壓縮檔案的時候新增密碼一樣,開啟壓縮檔案需要輸入密碼才能訪問裡面的內容。起初我所做的專案本身就是二次開發,要在前人地基礎上進行新增密碼,之前是已經有了壓縮檔案的程式碼了,只不過是使用的官方的ZipOutputStream
和ZipEntry
結合使用壓縮的,我查了下官方api好像沒有提供加密的。
這時候我就找了zip4j這個庫,但是我查詢了下http://www.lingala.net/zip4j.html 官網使用方法,具體使用方法
當然使用方法都是以java平臺為例,直接是訪問的windows上的路徑,對於android來說,現在都是使用的Uri的路徑,而zip4j是使用File的路徑,當然現在Android還是可以使用File內部儲存進行操作訪問的,但是對於外部儲存,比如otg連線的U盤。
首先我們android使用的時候使用的編譯器是Android studio,使用build.gradle
來匯入庫的,
官方給出的是:
Maven
<dependency>
<groupId> net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>1.3.3</version>
</dependency>
當然我們as匯入直接複製上面一段程式碼,然後在build.gradle
中直接貼上就行了
直接會變成該有的匯入方式。
匯入完成重新載入下就可以使用了。
當然現在官網已經更新到2.6.x,我為什麼要用1.3.x的原因
1.首先是新版對我現在的app不友好。
2.還有就是網上大部分的使用資料都是1.3.x的,時間有限也不能慢慢去研究新用法了,所以就近原則。
首先先看看我原先的程式碼
當然這是我專案的程式碼塊,用於說明,我儘量講解一下,不然我自己到時候看都不是很清楚,
首先
val packTarPath = String.format(BACKUP_INFO_PATH, backupDirectory)
val outputStream = UsbFileStreamFactory.createBufferedOutputStream(
checkExist(
usbDevices.getUsbFile(context),
packTarPath
)?.createFile(BACKUP_DATA_NAME)
)
這一塊是在我建立的壓縮檔案要放的路徑和檢查路徑是否存在並建立,BACKUP_DATA_NAME
是壓縮包的檔名當然要帶字尾名的,因為要提取檔案流outputStream
(BufferedOutputStream),這裡我要注意的地方就是我開始所說的,我這裡的路徑是Uri
不是File
路徑,因為使用File
的路徑在外部儲存裝置上進行建立zip包是拒絕訪問的,當然我現在是Android10,所以這裡是使用Uri來建立並獲取檔案流的。context.contentResolver.openOutputStream(自己的uri)
,至於獲取外部儲存的uri網上就大把了。
//建立ZIP
val outZip = ZipOutputStream(outputStream)
Utils.compress(pas, usbFile, outZip, usbFile?.name, true, it)
//完成和關閉
outZip.finish()
outZip.close()
outputStream?.close()
然後這裡就開始建立zip檔案了,這裡使用的ZipOutputStream
是zip4j裡面的而不是自帶的那個,
Utils.compress(pas, usbFile, outZip, usbFile?.name, true, it)
開始壓縮,大概看一下。
下面是主要部分:
/**
* 遞迴壓縮方法
*
* @param sourceFile 原始檔
* @param zos zip輸出流
* @param name 壓縮後的名稱
* @param KeepDirStructure 是否保留原來的目錄結構,true:保留目錄結構;
* false:所有檔案跑到壓縮包根目錄下(注意:不保留目錄結構可能會出現同名檔案,會壓縮失敗)
* @throws Exception
*/
public static void compress(String pas,UsbFile sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure, ObservableEmitter<PackTarModel> it) throws Exception {
byte[] buf = new byte[4 * 1024];
if (sourceFile.isFile()) {
//設定加密
ZipParameters para = new ZipParameters();
// 壓縮方式
para.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
para.setFileNameInZip(name);
para.setSourceExternalStream(true);
// 壓縮級別
para.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
para.setEncryptFiles(true);
para.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
para.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
para.setPassword(pas);
// 向zip輸出流中新增一個zip實體,構造器中name為zip實體的檔案的名字
zos.putNextEntry(new File(name), para);
it.onNext(new PackTarModel(sourceFile.getAbsolutePath(), 0));
// copy檔案到zip輸出流中
int len;
InputStream in = sourceFile.getInputStream();
while ((len = in.read(buf)) != -1) {
zos.write(buf, 0, len);
}
// Complete the entry
zos.closeEntry();
in.close();
} else {
UsbFile[] listFiles = sourceFile.listFiles();
if (listFiles == null || listFiles.length == 0) {
// 需要保留原來的檔案結構時,需要對空資料夾進行處理
if (KeepDirStructure) {
// 空資料夾的處理
zos.putNextEntry(new File(name + "/"), new ZipParameters());
// 沒有檔案,不需要檔案的copy
zos.closeEntry();
}
} else {
for (UsbFile file : listFiles) {
// 判斷是否需要保留原來的檔案結構
if (KeepDirStructure) {
// 注意:file.getName()前面需要帶上父資料夾的名字加一斜槓,
// 不然最後壓縮包中就不能保留原來的檔案結構,即:所有檔案都跑到壓縮包根目錄下了
compress(pas,file, zos, name + "/" + file.getName(), KeepDirStructure, it);
} else {
compress(pas,file, zos, file.getName(), KeepDirStructure, it);
}
}
}
}
}
第一個引數是後面加的密碼,在這裡所用的ZipOutputStream
是zip4j裡面的,這裡的操作ZipParameters
就是為壓縮檔案設定條件,zos.putNextEntry(new File(name), para);
其實這裡與自帶的ZipOutputStream
的區別是,自帶的引數是ZipEntry
這個物件就可以了,而zip4j的是是個File
物件和ZipParameters
就可以了,當然是為了加密才使用的,沒有加密的需求用自帶的也是可以的。ZipEntry和File
都放的是檔名,所以這個沒啥好說的。後面就正常操作,判斷檔案路徑和檔案。
本文章也主要是對自己所遇到的難題,做記錄和學習,對廣大朋友有小小的幫助是最好的,或者有問題的地方提出來討論下,小生不才,有問題還望指出。嘻嘻