Como fazer upload de um grande arquivo para o servidor usando o retrofit multipart

0

Pergunta

Eu tenho o pedido, que funciona bem no carteiro:

enter image description here

e eu estou tentando fazer isso com o Retrofit. Em geral, os tamanhos de arquivo será >500MB de que. Fiz método de envio:

fun uploadFile(file:File) {

        val client = OkHttpClient().newBuilder()
            .build()
        val mediaType: MediaType? = "text/plain".toMediaTypeOrNull()
        val body: RequestBody = MultipartBody.Builder().setType(MultipartBody.FORM)
            .addFormDataPart(
                "data", file.name,
                file.asRequestBody()
            )
            .build()
        val request: Request = Request.Builder()
            .url("https://..../upload.php")
            .method("POST", body)
            .build()
        val response: okhttp3.Response = client.newCall(request).execute()

       println(response.message)
    }

mas eu preciso ter o arquivo para fazer o upload. Eu posso criar o arquivo temporário com o tal forma:

val path = requireContext().cacheDir
val file = File.createTempFile(
    name ?: "",
    fileUri.lastPathSegment,
    path
)
val os = FileOutputStream(file)
os.write(string)
os.close()

mas eu costumo receber outOfMemoryException. Eu também adicionado ao AndroidManifest.xml pilha param:

android:largeHeap="true"

mas isso não me ajuda em tudo durante temp ficheiro a criar. Eu não sei como carteiro uploads de arquivos, mas em geral, eu consegui fazer o upload com a sua ajuda arquivo com tamanho de cerca de 600 mb. Eu também posso cortar arquivo selecionado com pedaços:

val data = result.data
data?.let {
      val fileUri = data.data
      var name: String? = null
      var size: Long? = null
      fileUri.let { returnUri ->
            contentResolver?.query(returnUri!!, null, null, null, null)
      }?.use { cursor ->
            val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)

            cursor.moveToFirst()
            name = cursor.getString(nameIndex)
            size = cursor.getLong(sizeIndex)
       }


val inputStream: InputStream? = fileUri?.let { it1 ->
    contentResolver.openInputStream(
        it1
    )
}

val fileData = inputStream?.readBytes()
val mimeType = fileUri.let { returnUri ->
returnUri.let { retUri ->
    if (retUri != null) {
           contentResolver.getType(retUri)
    }
}
}


fileData?.let {
       val MAX_SUB_SIZE = 4194304 // 4*1024*1024 == 4MB
       var start = 0 // From 0
       var end = MAX_SUB_SIZE // To MAX_SUB_SIZE bytes
       var subData: ByteArray // 4MB Sized Array

       val max = fileData.size
       if (max > 0) {
           while (end < max) {
                subData = fileData.copyOfRange(start, end)
                start = end
                end += MAX_SUB_SIZE
                if (end >= max) {
                    end = max
                }
                                
                println("file handling" + subData.size)



        }
     end-- // To avoid a padded zero
     subData = fileData.copyOfRange(start, end)
     println("file handling" + subData.size)
     }
   }
}

todas as ações serão feitas em:

 private val filesReceiver =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == Activity.RESULT_OK) {

             }
         }

então, eu não tenho qualquer caminho do arquivo em modo normal. De qualquer maneira eu acho que eu fiz algo errado.

ATUALIZAÇÃO

agora eu tenho o upload de arquivos a partir de inputStream:

 private fun doSomeNetworkStuff(file:InputStream, name:String) {
        GlobalScope.launch(Dispatchers.IO) {
            val client = OkHttpClient()
                .newBuilder()
                .protocols(listOf(Protocol.HTTP_1_1))
                .connectTimeout(10, TimeUnit.MINUTES)
                .readTimeout(10, TimeUnit.MINUTES)
                .build()
            val mediaType: MediaType? = "text/plain".toMediaTypeOrNull()
            val body: RequestBody = MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart(
                    "data", name,
                    file.readBytes().toRequestBody(mediaType)
                )
                .build()
            val request: Request = Request.Builder()
                .url("https://.../upload.php")
                .method("POST", body)
                .build()

            val response: Response = client.newCall(request).execute()

            println(response.body)
        }
    }

e receber esse erro:

java.lang.OutOfMemoryError: Failed to allocate a 173410912 byte allocation with 25165824 free bytes and 89MB until OOM, max allowed footprint 199761800, growth limit 268435456

mas eu posso carregar com este ficheiro de código com tamanho de cerca de 90mb

android
2021-11-24 05:56:49
2

Melhor resposta

1

O retrofit multipart coisas tem um membro que leva um Uri para um pedido de corpo.

Você tenta usar um para um Arquivo de instância.

2021-11-24 07:53:27

você pode esclarecer pls que o pessoal, porque eu vi esta pergunta stackoverflow.com/questions/34562950/... e utilizados pessoal dele
Andrew

Você viu somerhing para um uri lá? Para um fluxo de entrada?
blackapps

Google para inputstreamrequestbody.
blackapps

Eu tentei usar o fluxo de entrada, como você disse, mas com matriz de bytes de uso, e o meu método de envio falha no tamanho do arquivo > 90mb, você pode verificar a minha pergunta upd pls?
Andrew

Eu só fiz dizer para usar a uri. Parece que você não está fazendo isso. Você não deve usar uma matriz de bytes. Ou um stream de entrada. Bem... dessa forma, Não.
blackapps

talvez você pode adicionar alguns exemplos, porque eu fiz ele como você entendeu, talvez você saiba melhor do que eu?) porque eu não encontrei qualquer menção sobre o uri para requestbody
Andrew

0

Você definir o log in loggingInterceptor ou restadapter ?
se sim, então tente definir NENHUM.

2021-11-24 06:14:28

ele já está feito
Andrew

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................