Skip to content

Commit 4b2b80e

Browse files
authored
refactor: copy streams differently (#842)
* refactor: copy streams differently * Create twenty-bikes-hunt.md
1 parent 6421df9 commit 4b2b80e

File tree

2 files changed

+37
-33
lines changed

2 files changed

+37
-33
lines changed

.changeset/twenty-bikes-hunt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-native-documents/picker": patch
3+
---
4+
5+
refactor: copy streams differently

packages/document-picker/android/src/main/java/com/reactnativedocumentpicker/FileOperations.kt

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package com.reactnativedocumentpicker
33
import android.content.ContentResolver
44
import android.content.Context
55
import android.net.Uri
6+
import android.os.Build
7+
import android.os.FileUtils
68
import com.facebook.react.bridge.Arguments
79
import com.facebook.react.bridge.ReactApplicationContext
810
import com.facebook.react.bridge.ReactContext
@@ -18,7 +20,7 @@ import java.io.FileNotFoundException
1820
import java.io.FileOutputStream
1921
import java.io.IOException
2022
import java.io.InputStream
21-
import java.nio.channels.Channels
23+
import java.io.OutputStream
2224
import java.util.UUID
2325

2426
class FileOperations(private val uriMap: MutableMap<String, Uri>) {
@@ -119,23 +121,17 @@ class FileOperations(private val uriMap: MutableMap<String, Uri>) {
119121
val destFileSafe = safeGetDestination(attemptedDestFile, destinationDir)
120122

121123
val copyStreamToFile: (InputStream?) -> Unit = { inputStream ->
122-
if (inputStream == null) {
123-
throw FileNotFoundException("No input stream was found for the source file")
124-
}
125-
FileOutputStream(destFileSafe).channel.use { destinationFileChannel ->
126-
val inputChannel = Channels.newChannel(inputStream)
127-
val size = destinationFileChannel.transferFrom(inputChannel, 0, Long.MAX_VALUE)
128-
if (size == 0L) {
129-
throw IOException("No data was copied to the destination file")
130-
}
124+
inputStream ?: throw FileNotFoundException("No input stream was found for the source file")
125+
val bytesCopied = copyStreamToAnother(inputStream, FileOutputStream(destFileSafe))
126+
if (bytesCopied == 0L) {
127+
throw IOException("No data was copied to the destination file")
131128
}
132129
}
133130

134131
if (convertVirtualFileAsType == null) {
135-
context.contentResolver.openInputStream(from).use(copyStreamToFile)
132+
copyStreamToFile(context.contentResolver.openInputStream(from))
136133
} else {
137-
getInputStreamForVirtualFile(context.contentResolver, from, convertVirtualFileAsType)
138-
.use(copyStreamToFile)
134+
copyStreamToFile(getInputStreamForVirtualFile(context.contentResolver, from, convertVirtualFileAsType))
139135
}
140136

141137
return destFileSafe
@@ -161,9 +157,7 @@ class FileOperations(private val uriMap: MutableMap<String, Uri>) {
161157
}
162158

163159
fun writeDocumentImpl(sourceUri: Uri?, targetUriString: String?, context: ReactApplicationContext): DocumentMetadataBuilder {
164-
if (sourceUri == null) {
165-
throw IllegalArgumentException("The source URI is null. Call saveDocument() before writeDocument()")
166-
}
160+
sourceUri ?: throw IllegalArgumentException("The source URI is null. Call saveDocument() before writeDocument()")
167161
val targetUri: Uri? = uriMap[targetUriString]
168162

169163
if (targetUri == null) {
@@ -180,25 +174,30 @@ class FileOperations(private val uriMap: MutableMap<String, Uri>) {
180174
val mimeFromUri = contentResolver.getType(targetUri)
181175
metadataBuilder.mimeType(mimeFromUri)
182176

183-
// TODO https://gist.github.com/vonovak/73affb1a5b904ee165d9b5981d8dfe9a
184-
contentResolver.openInputStream(sourceUri).use { inputStream ->
185-
if (inputStream == null) {
186-
metadataBuilder.metadataReadingError("No output stream found for source file")
187-
} else {
188-
contentResolver.openOutputStream(targetUri).use { outputStream ->
189-
if (outputStream == null) {
190-
metadataBuilder.metadataReadingError("No output stream found for destination file")
191-
} else {
192-
val bytesCopied = inputStream.copyTo(outputStream)
193-
if (bytesCopied == 0L) {
194-
metadataBuilder.metadataReadingError("No data was copied to the destination file")
195-
}
196-
outputStream.flush()
197-
}
198-
}
199-
}
177+
val inputStream = contentResolver.openInputStream(sourceUri)
178+
?: return metadataBuilder.metadataReadingError("No input stream found for source file")
179+
180+
val outputStream = contentResolver.openOutputStream(targetUri)
181+
?: return metadataBuilder.metadataReadingError("No output stream found for destination file")
182+
183+
val bytesCopied = copyStreamToAnother(inputStream, outputStream)
184+
if (bytesCopied == 0L) {
185+
metadataBuilder.metadataReadingError("No data was copied to the destination file")
200186
}
201187

202188
return metadataBuilder
203189
}
190+
191+
val copyStreamToAnother: (InputStream, OutputStream) -> Long = { inputStream, outputStream ->
192+
inputStream.use { input ->
193+
outputStream.use { output ->
194+
val bytesCopied = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
195+
FileUtils.copy(inputStream, outputStream)
196+
} else {
197+
inputStream.copyTo(outputStream)
198+
}
199+
return@use bytesCopied
200+
}
201+
}
202+
}
204203
}

0 commit comments

Comments
 (0)