@@ -24,16 +24,15 @@ import aws.smithy.kotlin.runtime.content.ByteStream
2424import aws.smithy.kotlin.runtime.content.writeToFile
2525import aws.smithy.kotlin.runtime.io.SdkSource
2626import aws.smithy.kotlin.runtime.io.buffer
27+ import com.amplifyframework.storage.s3.transfer.ClearableBufferedOutputStream
2728import com.amplifyframework.storage.s3.transfer.DownloadProgressListener
2829import com.amplifyframework.storage.s3.transfer.DownloadProgressListenerInterceptor
2930import com.amplifyframework.storage.s3.transfer.StorageTransferClientProvider
3031import com.amplifyframework.storage.s3.transfer.TransferDB
3132import com.amplifyframework.storage.s3.transfer.TransferStatusUpdater
32- import java.io.BufferedOutputStream
3333import java.io.File
3434import java.io.FileOutputStream
3535import kotlinx.coroutines.Dispatchers
36- import kotlinx.coroutines.currentCoroutineContext
3736import kotlinx.coroutines.isActive
3837import kotlinx.coroutines.withContext
3938
@@ -101,9 +100,11 @@ internal class DownloadWorker(
101100 val append = file.length() > 0
102101 val fileOutputStream = FileOutputStream (file, append)
103102 var totalRead = 0L
104- BufferedOutputStream (fileOutputStream).use { fileOutput ->
103+ // use ensures the underlying source is closed. In this case, a BufferedOutputStream. By default,
104+ // a bos flushes on close. We may not want this behavior, so we use ClearableBufferedOutputStream.
105+ ClearableBufferedOutputStream (fileOutputStream).use { fileOutput ->
105106 val copied = 0L
106- while (currentCoroutineContext(). isActive) {
107+ while (isActive) {
107108 val remaining = limit - copied
108109 if (remaining == 0L ) break
109110 val readBytes =
@@ -112,10 +113,24 @@ internal class DownloadWorker(
112113 if (readBytes > 0 ) {
113114 totalRead + = readBytes
114115 }
115- fileOutput.write(buffer, 0 , readBytes)
116+ if (isActive) {
117+ // Double check to make sure that we are still active before writing to buffer
118+ fileOutput.write(buffer, 0 , readBytes)
119+ } else {
120+ // If we are no longer active, clear the buffer so that no more data is written to the
121+ // file. A resume operation may have already started, and it resumes based on the
122+ // file size at its start. A flush here could result in duplicating file data
123+ fileOutput.clear()
124+ }
116125 }
117- if (sourceStream.buffer().exhausted()) {
126+ if (sourceStream.buffer().exhausted() && isActive) {
127+ // Double check to make sure that we are still active before flushing to buffer
118128 fileOutput.flush()
129+ } else {
130+ // If we are no longer active, clear the buffer so that no more data is written to the
131+ // file. A resume operation may have already started, and it resumes based on the
132+ // file size at its start. A flush here could result in duplicating file data
133+ fileOutput.clear()
119134 }
120135 }
121136 }
0 commit comments