開心一刻
一天夜裡,侄女跟我哥聊天
侄女一臉期待的看著我哥:爸爸,你說媽媽和奶奶誰漂亮啊?
我哥不慌不忙的拿起一粒瓜子,輕聲說道:為啥沒有你啊?
侄女笑容漸起,似乎得到了她想要的回答,仍繼續問道:那媽媽和奶奶還有我,誰漂亮?
我哥瞄了一眼侄女,又拿起一粒瓜子堅定的說到:奶奶!
侄女笑臉瞬間一拉,死死地盯著我哥,幽怨地問道:那裡為啥要加我呀?
我哥再次瞄了一眼侄女,繼續剝著瓜子說到:我不想讓你媽媽墊底!
侄女斜眼瞟向我哥,臉上寫滿了憤怒
一旁的我,肚子笑疼了!
背景需求
背景
專案基於 SpringBoot ,採用 B/S 模式
主要功能是生成檔案,然後將檔案上傳都 OSS
目前透過瀏覽器可以下載少量檔案,但一旦檔案過多或檔案過大(總體來說就是過大),瀏覽器下載會很慢,極其容易超時而失敗
需求
而最近頻繁接到產品那邊的反饋,說是要下載最近幾個月,甚至兩三年的某些檔案
總之就是要支援大批次檔案的下載
大批次下載實現
既然業務部門發話了,作為支撐部門,必須得全力以赴,那就整唄
阿里雲oss提供了三種下載檔案的方式:簡單下載、斷點續傳下載、授權給第三方下載
我們只看簡單下載,其他兩種方式大家自行去了解
簡單下載方式也分好幾種,我們一個個來看
OSS控制檯
OSS控制檯指的就是
然後按照如下步驟進行檔案下載
但有2點需要注意
1、不支援透過OSS控制檯下載資料夾(包含子目錄)
如果需要下載資料夾(包含子目錄),您可以使用ossbrowser、ossutil、SDK、API等方式進行下載
2、透過OSS控制檯可一次批次下載最多100個檔案
最多隻能下載100個檔案,多不了一點
很顯然這種方式不合適
1、檔案上傳到OSS的路徑規則導致每個檔案都在不同的資料夾下,結果就是隻能一個一個檔案下載
效率太低,誰操作誰得罵娘
2、批次下載的檔案資料很容易超過100
圖形化管理工具ossbrowser
關於 ossbrowser 不做過多介紹,大家直接查閱官網即可:圖形化管理工具ossbrowser
簡單點來說, ossbrowser 就是 OSS控制檯 的 C 端
所以也不合適,不合適點和 OSS控制檯 方式一樣
阿里雲SDK
目前已實現的少量檔案的下載,就是透過此種方式實現的
產品透過瀏覽器請求後端,後端透過 阿里雲SDK 將檔案下載到後端伺服器,下載完成之後進行打包,最後將打包檔案以流的方式透過瀏覽器儲存到產品電腦的指定資料夾下
一旦打包檔案很大,透過瀏覽器就很容易超時失敗
那就不透過瀏覽器唄,後端將打包檔案上傳到指定的FTP伺服器的指定目錄下,然後產品去FTP伺服器上的指定目錄下拿打包檔案
看似可行,但還是有一些不容忽視的不足
1、需要一臺FTP伺服器,而且需要對這臺FTP伺服器進行維護
2、產品需要從FTP拿打包檔案,如果打包檔案很大,這個複製過程也很費時
所以這種方式也不是很合適
命令列工具ossutil
關於 ossutil ,命令列工具ossutil已經講的很詳細了
使用 ossutil 之前,需要先配置它,大家按照配置ossutil配置即可
需要強調的一點是,如果僅僅只是下載,那麼配置的時候用 bucket 的只讀賬號即可
本次下載只用到了ls、cp兩個命令,我們來看下這兩個命令的使用
ossutil64 ls oss://qsl-yzb-test/UserData/9088/20230920
ossutil64 cp oss://qsl-yzb-test/UserData/9088/20230920/Snipaste_2023-09-25_16-24-39.png D:\qsl-yzb-test\20230920\
我們發現,檔案已經下載到 D:\qsl-yzb-test\20230920 目錄下
感覺跟需求很吻合,如果能從單個下載改成批次下載,那麼需求就實現了
一次輸入一個 CMD 命令,顯然是不行的,需要以 bat 指令碼的方式實現多命令的執行,完成檔案的下載
假設我們要下載 1011、9088、9999 這三個資源202308、202309兩個月的檔案, bat 指令碼該如何寫?
我們用兩個配置檔案來配置資源和月份,類似如下
bat 的 for 很強大,尤其以 for /f 最強,格式如下
分別對應檔案、字串、命令
我們先用 for /f 來讀取兩個配置檔案
執行結果如下
有 2 點需要注意
1、 cmd 下,變數用一個 % 來表示,比如 %r,示例:
但是批處理(bat指令碼)時,變數需要 %% 來表示,比如 %%r
2、for命令的形式變數只能是26個字母中的任意一個,同時區分大小寫
配置檔案的解析已經實現,接下來需要結合 ossutil 的命令來實現檔案的下載了
一步一步來,我們先結合 ossutil 的 ls 命令獲取檔案列表
ossutil64 ls oss://qsl-yzb-test/UserData/9999/202309 結果如下
我們關注的其實只是 ObjectName 那一列,而 for /f 正好能實現
for /f "tokens=8 delims= " %p in ('ossutil64 ls oss://qsl-yzb-test/UserData/9999/202309') do echo %p
效果如下
delims=符號列表 :以指定符號列表對字串進行切割,如果沒有指定 delims ,那麼預設則以空格鍵或跳格鍵作為分隔符號
for /f "delims= " 和 for /f 是一樣的效果
tokens=n :定點提取第 n 個字串
tokens 後可以接多個數字,以逗號隔開,例如: tokens=2,5,8
delims 進行切割, tokens 獲取切割後指定位置的字串
放進 bat 指令碼
執行結果如下
我們需要的是檔案列表,不需要關注目錄,那如何過濾掉目錄了?
ossutil 的 ls 命令正好有 --include 引數能實現過濾
執行結果如下
oss檔案路徑已經獲取到,接下來就是結合 cp 命令進行下載了
執行後, D:\qsl-yzb-test 目錄下檔案如下
離成功還差一步之遙,需要將檔案按日期進行劃分,比如 20230921 這天的所有檔案全部放到 20230921 這個目錄下
oss檔案路徑是有規則的,具體檔名的上一級目錄就是日期目錄,所以我們可以從oss路徑中擷取日期目錄, for /f 正好能實現
執行後, D:\qsl-yzb-test 目錄內容如下
自此,算是大功告成了
但如果能手動指定下載目錄就好了(下載目錄作為 bat 引數)
這個很簡單,直接上程式碼
完整指令碼程式碼
@ECHO OFF rem 字元編碼設定成UTF-8編碼,防止中文亂碼 chcp 65001 rem %1 下載目錄 if "%1"=="" ( echo "請指定下載目錄,類似 D:\qsl-yzb-test" goto :eof ) for /f %%r in (resource_config.txt) do ( for /f %%m in (month_config.txt) do ( for /f "tokens=8 delims= " %%p in ('ossutil64 ls oss://qsl-yzb-test/UserData/%%r/%%m --include *.*') do ( for /f "tokens=5 delims=/" %%d in ("%%p") do ( rem -f表示同名覆蓋 ossutil64 cp %%p %1\%%d\ -f ) ) ) )
REST API
自定義要求較高的情況可以考慮這種方式,感興趣的可以去看官方說明
總結
1、 ossutil 提供了很多命令,實現需求之前可以先翻一翻官方文件說明
2、 cmd 和 bat 的變數命名是有區別的,大家一定要注意
3、 for 很強大, for /f 強大的最突出