Come caricare file di grandi dimensioni al server utilizzando il retrofit multipart

0

Domanda

Ho la richiesta, che funziona bene in postino:

enter image description here

e sto cercando di farlo con Retrofit. In generale, file di dimensioni >500 MB che. Ho fatto un tale metodo di caricamento:

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)
    }

ma ho bisogno di avere il file per il caricamento. Posso creare il file temporaneo con tale modo:

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

ma io di solito ricevono outOfMemoryException. Ho aggiunto anche per la AndroidManifest.xml heap param:

android:largeHeap="true"

ma non mi ha aiutato durante tutta la temp file di creazione. Non so come postino upload di file, ma in generale sono riuscito a caricare con il suo aiuto di file con una dimensione di circa 600Mb. Posso anche tagliare file selezionato con blocchi:

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)
     }
   }
}

tutte le azioni saranno realizzate in:

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

             }
         }

così non avrò alcun percorso del file in modo normale. Comunque penso di aver fatto qualcosa di sbagliato.

AGGIORNAMENTO

adesso ho l'upload di file da 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 ricevere tale errore:

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

ma posso caricare con questo codice file con dimensioni di circa 90mb

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

Migliore risposta

1

Il retrofit multipart roba ha un membro che accetta un Uri per la richiesta del corpo.

Si tenta di utilizzare l'uno per un File di esempio.

2021-11-24 07:53:27

puoi chiarire pls che personale, perché ho visto questa domanda stackoverflow.com/questions/34562950/... e utilizzati dal personale da lui
Andrew

Hai visto somerhing per un uri che c'è? Per un flusso di input?
blackapps

Google per inputstreamrequestbody.
blackapps

Ho cercato di utilizzare gli stream di input, come hai detto tu, ma con una matrice di byte di utilizzo, e il mio metodo di caricamento non riesce a file di dimensioni > 90mb, potete controllare la mia domanda upd pls?
Andrew

Ho fatto solo dire di usare l'uri. Sembra che non stiate facendo. Non si deve usare un array di byte. O un flusso di input. Beh... Non in questo modo.
blackapps

forse si può aggiungere un po ' di esempio, perché l'ho fatto come capito, forse tu lo sai meglio che me?) perché non ho trovato notizie sull'uri per requestbody
Andrew

0

Ti sei imposta di registro in loggingInterceptor o restadapter ?
se sì, allora prova a regolarla NESSUNO.

2021-11-24 06:14:28

e ' già stato fatto
Andrew

In altre lingue

Questa pagina è in altre lingue

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