Как загрузить большой файл на сервер с помощью модифицированного составного

0

Вопрос

У меня есть просьба, которая хорошо работает в postman:

enter image description here

и я пытаюсь сделать это с помощью модернизации. В общем случае размеры файлов будут >500 МБ, что. Я сделал такой способ загрузки:

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

но мне нужен файл для загрузки. Я могу создать временный файл таким способом:

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

но я обычно получаю outOfMemoryException. Я также добавил к AndroidManifest.xml параметры кучи:

android:largeHeap="true"

но это совсем не помогло мне во время создания временного файла. Я не знаю, как почтальон загружает файлы, но в целом мне удалось загрузить с его помощью файл размером около 600 МБ. Я также могу вырезать выбранный файл кусками:

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

все действия будут выполнены в:

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

             }
         }

поэтому у меня не будет никакого пути к файлу обычным способом. В любом случае, я думаю, что сделал что-то не так.

Обновить

прямо сейчас у меня есть такая загрузка файлов из 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)
        }
    }

и получите такую ошибку:

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

но я могу загрузить с помощью этого файла кода размером около 90 МБ

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

Лучший ответ

1

В составном материале модернизации есть элемент, который принимает Uri для тела запроса.

Вы пытаетесь использовать его для экземпляра файла.

2021-11-24 07:53:27

можете ли вы уточнить, пожалуйста, какой персонал, потому что я видел этот вопрос stackoverflow.com/questions/34562950/... и использовал посох от него
Andrew

Вы видели там кого-нибудь, кто искал ури? Включено для входного потока?
blackapps

Поиск в Google по запросу inputstreamrequestbody.
blackapps

Я пытался использовать входной поток, как вы сказали, но с использованием массива байтов, и мой метод загрузки не работает при размере файла > 90 МБ, можете ли вы проверить мой вопрос, пожалуйста?
Andrew

Я только сказал использовать uri. Похоже, вы этого не делаете. Вы не должны использовать массив байтов. Или входной поток. Хорошо... Не в этом смысле.
blackapps

может быть, вы можете добавить какой-нибудь образец, потому что я сделал это так, как понял вас, может быть, вы знаете лучше, чем я?) потому что я не нашел никаких упоминаний об uri для запроса
Andrew

0

Вы установили логин в loggingInterceptor или restadapter ?
если да, то попробуйте установить его НЕТ.

2021-11-24 06:14:28

это уже сделано
Andrew

На других языках

Эта страница на других языках

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