iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0

前言

  • 預計寫好這個函式後,就可以在登入後,透過查詢使用者帳號、從圖庫資料庫中撈取使用者傳過的圖,載回手機。
  • 昨天提到,圖片雖然可以上傳,但大家都把圖扔到相同目錄,會無法區分是誰放上來的,又該還給誰。

規劃修改內容

  • 嘗試解決檔名碰撞的議題
    • 不同使用者之間,在每個使用者丟上檔案時
      • 加一層可以識別使用者的目錄名稱,例如使用者的 /public/user_id_1/
        • 優點:直覺,不用額外去記錄對應關係。
        • 缺點:可能是會被 URL Traversal⋯⋯會嗎?極可能會! 如果我這個 APP 被反組譯,就會被魔改...又或者是說,根本不需要反組譯,因為我都把程式碼公開在我的 GitHub 了🙄️
    • 在同個使用者不同時間點所丟上來的同名魚
      • 可以透過多加一層魚名稱的目錄、/public/user_id_1/台灣鯛/202309252350.png
        • 優點:會多出好多種類的魚名字目錄,我覺得之後可能會帶來的好處是可以方便拿資料來訓練。
        • 缺點:不同名稱的魚,因為多了目錄的區隔,想要用一次查詢取回來,要絞盡腦汁設計 filter。
      • 使用流水號目錄,會難以辨別,打槍
      • 使用時戳目錄,如 /public/user_id_1/20230925/台灣鯛.png
        • 優點:如果要記錄活動而言,這是一個很好的檔案結構,從 S3 列出目錄就直接對應到活動日期,一次可以拿為當時抓到的所有魚。
        • 缺點:但對於老是打龜的人,這簡直就是種羞辱。
      • 不使用目錄分割,如 /public/user_id_1/台灣鯛_202309252350.png
        • 優點:上面討論了一堆,每種做法都會修改到檔名,檔名一定會有時戳或流水號。不根據魚的名稱分目錄,好處就是可以在提取所有圖片時更直覺。
        • 缺點:所有的東西都摻在一起,省了指令呼叫的成本而已,相對地,資料傳輸比較貴,要是拿到額外不需要的圖,就噴大錢了。

小結

  • 在進行相片五部曲之五拿回資料前,先修改檔案擺放的方式!!而這個修改方式寫在 【Day 25】 會員專屬相簿: 透過 Amplify Auth 識別、建立 S3 目錄結構
  • 希望將路徑做成下圖這個排列方式
    https://ithelp.ithome.com.tw/upload/images/20230928/20130149uY9mDq42dK.png
  • 以信箱地址建立目錄,可以區隔上傳的人是誰。
  • 還可以根據他的魚的命名方式建立第二層目錄,以方便我們後續整理和訓練。
  • 相片嘛,不能都叫 AA魚BB魚 這種固定名字,以避免同名碰撞。最有用的訊息就是時戳啦!

原始碼

  • 以下程式碼部分,從印出 "==============" 分成上下兩部份來看:
    • 上半部,先做出一個空白的陣列 toBeDownloadedList 用來記錄抓到雲端儲存空間的檔案位置 (Key)
    • 下半部,拆解 Key 之後,如 xxx@gmail.com/生魚片/20230930161239.png 可以分別拿到使用者名稱、魚魚名稱、打成時戳樣子的檔案名稱。
    • 下載下來,依序排好。
    • 修改部分可以參考 github commit
func fetchStamp() async {
    print("Fetch Amplify S3 Fish dir")
    let attrs = await fetchUserAttr()
    let username = attrs["name"] ?? "guest"
    var toBeDownloadedList:[String] = []

    // Base Dir
    let manager = FileManager.default
    guard let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first else {
        return
    }

    do {
        let options = StorageListRequest.Options(path:username, pageSize: 1000)
        let listResult = try await Amplify.Storage.list(options: options)
        listResult.items.forEach { item in
            print("Key: \(item.key)")
            toBeDownloadedList.append(item.key)
            // Key: email/生魚片/20230930161239.png
        }
    } catch {
        print("failed to fetch s3 file key")
    }
    print("==============")
    for picKey in toBeDownloadedList {
        print(picKey)
        let pathSplit = picKey.split(separator: ["/"])
        let localFileUrl = url.appendingPathComponent("saved/pics/\(pathSplit[1])/\(pathSplit[2])")
        // Create fish dir
        let localFishDir = url.appendingPathComponent("saved/pics/\(pathSplit[1])")
        do {
            try manager.createDirectory(at: localFishDir, withIntermediateDirectories: true)
        } catch {
            print(error)
        }
        // Start download
        let downloadTask = Amplify.Storage.downloadFile(
            key: picKey,
            local: localFileUrl,
            options: nil
        )
        do {
            try await downloadTask.value
            print("Completed: \(picKey)")
            stamps.append(Stamp(imgName: "/saved/pics/\(pathSplit[1])/\(pathSplit[2])",
                                 fishName: String(pathSplit[1]),
                                 catched: 1, counted: 1)
            )
        } catch {
            print("failed to download")
        }
    }
}

備註

  • 使用 Assets
    1. 寫:製作程式時,放入 Assets.xcassets (只能在製作程式的時候放進去,程式不能寫資料進來)
    2. 讀:直接由 Image("圖檔名字") 取用
  • 相片五部曲
    1. 拍照或讀取照相簿 ImagePickerUIImage
    2. UIImage離線 PNG 檔案
    3. 離線 PNG 檔案Image
    4. 離線 PNG 檔案S3
    5. S3離線 PNG 檔案

上一篇
【Day 23】 相片五部曲之四:從離線 PNG 檔案至 S3
下一篇
【Day 25】 會員專屬相簿: 透過 Amplify Auth 識別、建立 S3 目錄結構
系列文
依然無法成為釣魚大師也要努力摸魚!!辣個吃魚神器 APP 第二彈33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言