記一次 OSS 大批量文件下載的實現 → bat腳本不好玩!

開心一刻

  一天夜裏,侄女跟我哥聊天

  侄女一臉期待的看着我哥:爸爸,你說媽媽和奶奶誰漂亮啊?

  我哥不慌不忙的拿起一粒瓜子,輕聲說道:爲啥沒有你啊?

  侄女笑容漸起,似乎得到了她想要的回答,仍繼續問道:那媽媽和奶奶還有我,誰漂亮?

  我哥瞄了一眼侄女,又拿起一粒瓜子堅定的說到:奶奶!

  侄女笑臉瞬間一拉,死死地盯着我哥,幽怨地問道:那裏爲啥要加我呀?

  我哥再次瞄了一眼侄女,繼續剝着瓜子說到:我不想讓你媽媽墊底!

  侄女斜眼瞟向我哥,臉上寫滿了憤怒

  一旁的我,肚子笑疼了!

背景需求

  背景

  項目基於 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 的只讀賬號即可

  本次下載只用到了lscp兩個命令,我們來看下這兩個命令的使用

   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
            )
        )
    )
)
View Code

  REST API

  自定義要求較高的情況可以考慮這種方式,感興趣的可以去看官方說明

總結

  1、 ossutil 提供了很多命令,實現需求之前可以先翻一翻官方文檔說明

  2、 cmd 和 bat 的變量命名是有區別的,大家一定要注意

  3、 for 很強大, for /f 強大的最突出

參考

  批處理for語句從入門到精通

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章