【问题标题】:Amazon s3 upload multiple files android亚马逊s3上传多个文件android
【发布时间】:2017-09-05 16:23:56
【问题描述】:

如果有人仍在寻找解决方案,我最终在代码上使用了循环自爆,我没有找到用于上传多个文件的官方 api。

-------

我有一个 ImageFiles 的 ArrayList,我想上传到 Amazon s3。他们的文档提供了以下代码:

credentials = new BasicAWSCredentials(key, secret);
s3 = new AmazonS3Client(credentials);               
transferUtility = new TransferUtility(s3, getContext());
observer.setTransferListener(new TransferListener() {
    @Override
    public void onStateChanged(int id, TransferState state) {

    }

    @Override
    public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
    }

    @Override
    public void onError(int id, Exception ex) {

    }
});
observer = transferUtility.upload("buket name", upload_file.getNew_name(),
                                   new File(upload_file.getFile_path()));

但是这段代码只需要一个文件。如何一次上传多个文件?如果他们不允许这样做,那么用户可以提出更多请求,还有什么替代方法呢??

【问题讨论】:

    标签: android amazon-web-services


    【解决方案1】:

    我知道我回答迟了,但它会帮助其他来这里寻找答案的人。

    目前,上传多个文件的唯一选择是使用循环将列表中的文件作为单个文件传递,但这是我昨晚发现并实现的。到目前为止,我已经测试了很多次。

    这种方法的优点是它对每个文件同时运行,而不是等待每个文件都先上传或下载,然后再对下一个文件进行操作。

    这是我找到的 here,但我对其进行了一些修改以供在 Kotlin 中使用。

    • 首先,创建一个类,我将其命名为MultiUploaderS3 -

       import android.content.Context
       import com.amazonaws.mobileconnectors.s3.transferutility.TransferListener
       import com.amazonaws.mobileconnectors.s3.transferutility.TransferState
       import com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility
       import io.reactivex.Completable
       import io.reactivex.Observable
       import io.reactivex.Single
       import java.io.File
      
       class MultiUploaderS3 {
      
           private fun transferUtility(context: Context): Single<TransferUtility?>? {
               return Single.create { emitter ->
                   emitter.onSuccess(
                   TransferUtility(s3ClientInitialization(context), context)
                   )
               }
           }
      
           fun uploadMultiple(fileToKeyUploads: Map<File, String>, context: Context): Completable? {
               return transferUtility(context)!!
                   .flatMapCompletable { transferUtility ->
                       Observable.fromIterable(fileToKeyUploads.entries)
                           .flatMapCompletable { entry ->
                               uploadSingle(
                                   transferUtility,
                                   entry.key,
                                   entry.value
                               )
                           }
                   }
           }
      
               private fun uploadSingle(
               transferUtility: TransferUtility,
               aLocalFile: File?,
               toRemoteKey: String?
           ): Completable? {
               return Completable.create { emitter ->
                   transferUtility.upload(bucketName,toRemoteKey, aLocalFile)
                       .setTransferListener(object : TransferListener {
                           override fun onStateChanged(
                               id: Int,
                               state: TransferState
                           ) {
                               if (TransferState.FAILED == state) {
                                   emitter.onError(Exception("Transfer state was FAILED."))
                               } else if (TransferState.COMPLETED == state) {
                                   emitter.onComplete()
                               }
                           }
      
                           override fun onProgressChanged(
                               id: Int,
                               bytesCurrent: Long,
                               bytesTotal: Long
                           ) {
                           }
      
                           override fun onError(id: Int, exception: Exception) {
                               emitter.onError(exception)
                           }
                       })
               }
           }
      
       }
      
    • 我创建了一个返回 S3Client 的函数,如下 -

      fun s3ClientInitialization(context: Context): AmazonS3 {
          val cognitoCachingCredentialsProvider = CognitoCachingCredentialsProvider(
              context,
              your key,
              region
          )
          return AmazonS3Client(
              cognitoCachingCredentialsProvider,
              Region.getRegion(Regions.YOUR_REGION)
          )
      }
      
    • 那么,称它为-

       val map: Map<File, String> = yourArrayList.map {it to Your_Key_For_Each_File}.toMap()
       MultiUploaderS3().uploadMultiple(map, this)
           .subscribeOn(Schedulers.io())
           .observeOn(Schedulers.io())
           .subscribe {
               runOnUiThread {
                   Toast(this@AddActivity, "Uploading completed", Toast.LENGTH_LONG).show()
               }
            }
      

    我已经分享了完整的工作代码,您可以根据需要进行更改。您也可以在同一类中使用上述MultiUploaderS3 类,这显然会使访问TransferListener 变得更容易。

    对于下载,更改

    transferUtility.upload(bucketName,toRemoteKey, aLocalFile) in uploadSingle()

    transferUtility.download(bucketName, fromRemoteKey, aLocalFile)

    并将其称为

    val map: Map&lt;File, String&gt; = yourKeysArrayList.map {Your_FILE_For_Each_KEY to it}.toMap()

    这将做的是将本地文件路径的映射传递给密钥。

    我曾多次尝试一次上传 10 个文件,上传所有文件大约需要 4-5 秒,不过这也取决于您的互联网连接。我希望下载部分也能正常工作。询问我是否有任何事情或查看我的Github

    【讨论】:

      【解决方案2】:

      你可以为这个任务创建 observable

       public Observable<AWSFile> upload(List<String> paths) {
              List<Observable<AWSFile>> list = new ArrayList<>();
              for (String path: paths) {
                  list.add(upload(path));
              }
              return Observable.concat(list);
          }
      
      public Observable<AWSFile> upload(String filePath) {
              if (filePath == null) {
                  Log.d(TAG, "uploadWithTransferUtility: ");
                  return Observable.never();
              }
              return Observable.create(emitter -> {
                  File file = new File(filePath);
                  TransferObserver observer = awsUtil.getTransferUtility(context).upload(awsUtil.getAwsConstants().BUCKET_NAME, file);
                  observer.setTransferListener(new TransferListener() {
                      @Override
                      public void onStateChanged(int id, TransferState state) {
                          stateChanged(id, state);
                          emitter.onNext(new AWSFile(id,state,file.getName()));
                      }
      
                      @Override
                      public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
                          progressChanged(id, bytesCurrent, bytesTotal);
                      }
      
                      @Override
                      public void onError(int id, Exception ex) {
                          error(id,ex);
                          emitter.onError(ex);
                      }
                  });
                  emitter.setCancellable(observer::cleanTransferListener);
              });
      }
      

      这只是 sn-p,您可以将它用于多个文件或仅一个文件。

      编辑: AWSFile.java

      public class AWSFile {
          private int id;
          private TransferState newState;
          private String filename;
      }
      

      【讨论】:

      • AWSFile 是什么类?
      • 这是一个包装类,用于发送有关文件状态的更多信息。
      • @PiotrBadura 订阅了从upload(List) 方法返回的Observable&lt;AWSFile&gt;,它只调用一次onNext(),虽然我有很多项目,但我可能做错了什么?
      • 需要用onNext()打电话给onComplete()
      • 如果您遇到此答案,请在线程上订阅。
      【解决方案3】:

      您可以将上传代码移动到方法中并将文件路径传递给它。 然后您可以在文件路径列表上循环该方法。至少我是这样做的。如果您需要任何进一步的帮助,请告诉我。

      【讨论】:

      • 但这不是上传多张图片的正确方式,它应该是自动化的,不使用任何循环。
      【解决方案4】:

      @Lalit-Fauzdar 回答和提到的参考是解决问题的方法。我正在分享对实施的轻微升级

      class MultiUploaderS3Client(bucketName:String) {
      
          var bucketName = bucketName
      
          fun uploadMultiple(fileToKeyUploads: MutableMap<String,File>, transferUtility: TransferUtility): Completable? {
              return transferUtility(transferUtility)
                  .flatMapCompletable { transferUtility ->
                      Observable.fromIterable(fileToKeyUploads.entries)
                          .flatMapCompletable { entry ->
                              uploadSingle(
                                  transferUtility,
                                  entry.value,
                                  entry.key
                              )
                          }
                  }
          }
      
          private fun transferUtility(transferUtility: TransferUtility): Single<TransferUtility?> {
              return Single.create { emitter ->
                  emitter.onSuccess(
                      transferUtility
                  )
              }
          }
      
          private fun uploadSingle(
              transferUtility: TransferUtility?,
              aLocalFile: File?,
              toRemoteKey: String?
          ): Completable? {
              return Completable.create { emitter ->
                  transferUtility?.upload(bucketName,toRemoteKey, aLocalFile)
                      ?.setTransferListener(object : TransferListener {
                          override fun onStateChanged(
                              id: Int,
                              state: TransferState
                          ) {
                              if (TransferState.FAILED == state) {
                                  emitter.onError(Exception("Transfer state was FAILED."))
                              } else if (TransferState.COMPLETED == state) {
                                  emitter.onComplete()
                              }
                          }
      
                          override fun onProgressChanged(
                              id: Int,
                              bytesCurrent: Long,
                              bytesTotal: Long
                          ) {
                          }
      
                          override fun onError(id: Int, exception: Exception) {
                              emitter.onError(exception)
                          }
                      })
              }
          }
      
      }
      

      val multiUploadHashMap = mutableMapOf&lt;String,File&gt;()

      MultiUploaderS3Client(AWSConfig.misTicketFilesBucketName).uploadMultiple(multiUploadHashMap, transferUtility)
                              ?.subscribeOn(Schedulers.io())
                              ?.observeOn(Schedulers.io())
                              ?.subscribe {
                                  //Called when all files uploaded
                                  Runnable { callback.onComplete(_Result.Success<String>("uploaded successfully")) }
                                  handler.post(returnCallback)
                              }
      

      【讨论】:

        猜你喜欢
        • 2019-02-02
        • 2013-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-29
        • 2012-03-30
        相关资源
        最近更新 更多