0

我在 DropBox 论坛中的最初问题中交叉发布了这个。我认为对于 swiftydropbox 用户来说,这里也有这个很好。

我无法通过 swiftyDropbox 将整个文件夹下载到本地设备。我正在执行 ListFolder 和 ListFolderContinue (我观察到它将每个响应分成约 500 个文件)并将其附加到本地数组。

之后,我将此数组传递给 files.download。但是,我发现如果我的文件夹大于 1000 个文件(txt 文件大小约为 0.5-1kb),下载过程将不会开始。

static func downloadMissingFiles(client: DropboxClient, callingProcess: String) {
      let fileManager = FileManager.default
      let localBaseURL = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0].appendingPathComponent("Cloud/Dropbox", isDirectory: true)
      
      // Data will be in the form of
      // key   : "/workouts/workout list 1/peye.mrc"
      // value : "//workouts/workout list 1/peye.mrc=_-_=015ca880b135d01000000020cb26de0"
      for dbFiles in Array(dbFileNameRevDict) {
        let dbFilePathLower = dbFiles.key
        let dbFileNameRev = dbFiles.value
        let fullURL = localBaseURL.appendingPathComponent(dbFileNameRev)
        
        if fileManager.fileExists(atPath: fullURL.path) {
          print("  -> FILE EXISTS dbFileNameRev:\(dbFileNameRev)")
          localFileList.append(dbFileNameRev)
        } else {
          let destination : (URL, HTTPURLResponse) -> URL = { temporaryURL, response in
            return fullURL
          }
          
          client.files.download(path:dbFilePathLower, overwrite: true, destination: destination)
            .response { response, error in
              if let (_, url) = response {
                print("====> DOWNLOADED:\(url.lastPathComponent)")
              } else if let error = error {
               print(error)
            }
            /// This gives a progress of every single file on it's own. Hence, useless
            // .progress { progressData in
            //  print(progressData)
            // }
        }
      }
    }
  }

我尝试了各种方法来下载这些文件,我还尝试做一个串行队列来逐个迭代文件数组,但它不起作用。

这就是我处理 ListFolder 和 ListFolderContinue 的方式,查看 hasMore 属性。

      // https://stackoverflow.com/a/52870045/14414215
      if result.hasMore == true {
        processDBMore(client: client, cursor: result.cursor)
      } else {
        // When there is no more files (as indicated by hasMore == false)
        // start downloading the files
        downloadMissingFiles(client: client, callingProcess: "processDBMore-Finish")
        print("PrcessDBMore - dropboxGroup.leave")
        dropboxGroup.leave()
      }
4

1 回答 1

0

根据 Greg (swiftyDropbox)

每个“client.files.download”调用通过向 Dropbox API 服务器发出一个 HTTPS 请求来下载一个文件。此外,这些调用异步运行,并且在调用完成之前不会阻塞。也就是说,调用 'client.files.download' 将启动 HTTPS 请求,但它本身会在它完成和完全接收到响应之前返回。(一旦请求完成,它只会运行提供的块。)在这种情况下,在您在这里显示的代码中,您实际上几乎同时连续启动 1000 个连接,因此它可能会耗尽您的网络连接. 您应该更新您的代码,一次只提交一个(或几个)这些。您提到您尝试了一个串行队列,但这可能会遇到相同的问题,因为实际的请求是异步运行的。

因此,当我遇到这篇文章https://stackoverflow.com/a/66227963/14414215时,我正在寻找其他解决方案,这极大地帮助了我理解信号量的工作原理以及如何实现信号量(除了使用 dispatchGroups)能够正确控制files.download 调用。

   static func downloadMissingFiles(client: DropboxClient, callingProcess: String) {
      let fileManager = FileManager.default
      let localBaseURL = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0].appendingPathComponent("Cloud/Dropbox", isDirectory: true)
      let semaphore = DispatchSemaphore(value: 1)  // insert desired concurrent downloads value here.

      // Data will be in the form of
      // key   : "/workouts/workout list 1/peye.mrc"
      // value : "//workouts/workout list 1/peye.mrc=_-_=015ca880b135d01000000020cb26de0"
      DispatchQueue.global().async { // Wrap the call within an async block
      for dbFiles in Array(dbFileNameRevDict) {
        semaphore.wait() // Decrement the semaphore counter
        let dbFilePathLower = dbFiles.key
        let dbFileNameRev = dbFiles.value
        let fullURL = localBaseURL.appendingPathComponent(dbFileNameRev)
        
        if fileManager.fileExists(atPath: fullURL.path) {
          print("  -> FILE EXISTS dbFileNameRev:\(dbFileNameRev)")
          localFileList.append(dbFileNameRev)
          semaphore.signal()  // Increment semaphore counter
        } else {
          let destination : (URL, HTTPURLResponse) -> URL = { temporaryURL, response in
            return fullURL
          }
          
          client.files.download(path:dbFilePathLower, overwrite: true, destination: destination)
            .response { response, error in
              if let (_, url) = response {
                print("====> DOWNLOADED:\(url.lastPathComponent)")
                // we've reached here means we've successfully download the file
                // So we can (release)increment semaphore counter
                semaphore.signal() 
              } else if let error = error {
               print(error)
            }
            /// This gives a progress of every single file on it's own. Hence, useless
            // .progress { progressData in
            //  print(progressData)
            // }
        }
      }
    }
   }
  }
于 2021-08-28T07:54:26.123 回答