Android: retrofit file corrupted - android

I cannot open the pdf file I downloaded from the internet on my android device.
It gives the error that the file is corrupt. (corrupt file opens in pc)
//Request;
#GET("url")
suspend fun getDocumentDownload(#Path("File") file: String?): Response<ResponseBody>
//writeResponseBodyToDisk
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
val byteArray = ByteArray(4096)
val fileSize = body.contentLength()
var fileSizeDownloaded: Long = 0
inputStream = body.byteStream()
outputStream = FileOutputStream(file)
while (true) {
val read = inputStream.read(byteArray)
if (read == -1) {
break
}
outputStream.write(byteArray, 0, read)
fileSizeDownloaded += read.toLong()
}
outputStream.flush()
Response corrupt;
Response success;

Related

Issue with downloading files via Retrofit

I'm trying to download file via Retrfoit and everything goes well, until I'm opening it, because after that the only things that I see either a black screen (for images) or some kid of error about wrong file format. Can you tell me what am I doing wrong?
File creation sources:
val file = File(getExternalFilesDir(null), event.fileName)
ResponseBody converting sources:
private fun writeResponseBodyToDisk(body: ResponseBody, file: File): Boolean {
return try {
// todo change the file location/name according to your needs
val futureStudioIconFile: File = file
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
try {
val fileReader = ByteArray(4096)
val fileSize: Long = body.contentLength()
var fileSizeDownloaded: Long = 0
inputStream = body.byteStream()
outputStream = FileOutputStream(futureStudioIconFile)
while (true) {
val read: Int = inputStream.read(fileReader)
if (read == -1) {
break
}
outputStream.write(fileReader, 0, read)
fileSizeDownloaded += read.toLong()
Timber.d("%s%s", "file download: $fileSizeDownloaded of ", fileSize)
}
outputStream.flush()
viewState.value = ViewState.ShowFile(file)
true
} catch (e: IOException) {
false
} finally {
inputStream?.close()
outputStream?.close()
}
} catch (e: IOException) {
false
}
}
Viewwing sources:
val fileUri = FileProvider.getUriForFile(
this,
"${BuildConfig.APPLICATION_ID}.fileprovider",
state.file
)
startActivity(
Intent.createChooser(
Intent().apply {
action = Intent.ACTION_VIEW
putExtra(Intent.EXTRA_STREAM, fileUri)
clipData = ClipData.newRawUri("", fileUri)
type = "*/*"
addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
},
null
)
)
Logs:
file download: 4096 of 21688
file download: 8192 of 21688
file download: 12288 of 21688
file download: 16384 of 21688
file download: 20480 of 21688
file download: 21688 of 21688

Android download image with Workmanager and show it in gallery

I wrote code that downloads some source of data from the internet (in this example picture), shows downloadPercentages while the process of downloading is ongoing and writes this file on android storage. works well and looks very nice everything except saving on android storage.
Code is written in 3 classes, but I will show only one that I think is relevant (DownloadWorker). If anyone thinks other classes might help, let me now in comment and I will add them.
DownloadWorker:
class DownloadWorker(val context: Context, params: WorkerParameters) : Worker(context, params) {
companion object {
const val FILE_NAME = "image.jpg"
}
override fun doWork(): Result {
try {
if (DownloadHelper.url == null) {
DownloadHelper.downloadState.postValue(DownloadState.Failure)
return Result.failure()
}
DownloadHelper.url?.apply {
if(!startsWith("https")) {
DownloadHelper.url = replace("http", "https")
}
}
val url = URL(DownloadHelper.url)
val connection = url.openConnection()
connection.connect()
val fileSize = connection.contentLength
val inputStream = connection.getInputStream()
val buffer = ByteArray(1024)
val file = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
val outputFile = File(file, FILE_NAME)
var len = 0
var total = 0L
val fos = FileOutputStream(outputFile)
len = inputStream.read(buffer)
while (len != -1) {
fos.write(buffer, 0, len)
total += len
val percent = ((total * 100) / fileSize).toInt()
DownloadHelper.downloadState.postValue(DownloadState.InProgress(percent))
len = inputStream.read(buffer)
}
fos.close()
inputStream.close()
DownloadHelper.downloadState.postValue(DownloadState.Success(outputFile))
} catch (e: Exception) {
DownloadHelper.downloadState.postValue(DownloadState.Failure)
return Result.failure()
}
return Result.success()
}
}
After download success, my image is not shown in gallery, or in downloaded files folder. To see this image you need to enter android storage, find in android data app package by name and navigate all the way to the image. Pretty complicated.
Can anyone help, thanks.

cache: open failed: EISDIR (Is a directory) at libcore.io.IoBridge.open(IoBridge.java:492)

i'm trying to uploaed image but i got issues in
'val outputStream = FileOutputStream(file)'
```private var selectedImageUri: Uri? = null
if (selectedImageUri == null) {
layout_root.snackbar("Select an Image First")
return#setOnClickListener
}
val parcelFileDescriptor =
contentResolver.openFileDescriptor(selectedImageUri!!, "r", null) ?:
return#setOnClickListener
val inputStream = FileInputStream(parcelFileDescriptor.fileDescriptor)
val file = File(cacheDir, contentResolver.getFileName(selectedImageUri!!))
file.getParentFile().mkdirs();
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
val body = UploadRequestBody(file, "photoProfil", this) ```
[this is the error][1]

Encrypted File Transfer Could Not Be Recreated on Android

I am encrypting a file in Node.js client side and saving it on server as file, when I try to decrypt file it is not in the right format.
Encryptor.encryptFile = function (inputPath, outputPath, key, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options = Encryptor.combineOptions(options);
var keyBuf = new Buffer(key);
console.log(key)
var inputStream = fs.createReadStream(inputPath);
var outputStream = fs.createWriteStream(outputPath);
var cipher = crypto.createCipher(options.algorithm, keyBuf);
inputStream.on('data', function (data) {
console.log(data.length)
var buf = new Buffer(cipher.update(data));
outputStream.write(buf);
});
inputStream.on('end', function () {
try {
var buf = new Buffer(cipher.final('binary'), 'binary');
outputStream.write(buf);
outputStream.end();
outputStream.on('close', function () {
return callback();
});
} catch (e) {
fs.unlink(outputPath);
return callback(e);
}
});
};
Above is the encryption code, and on Android side I use the following code.
FIle Downloading:
Ion.with(this).load(documentModel.filePath)
.progress { downloaded, total -> println("$downloaded / $total") }
.write(file)
.setCallback { e, result ->
if (result != null) {
// val keys = MedpayDatabaseHelper.getInstance(this#ViewMedicalRecordActivity)?.keyDao()?.getKeys()
val handler = EncryptionHandler()
val decrepted = handler.decryptFile(handler.getSymmetricKey(), result)
val outfile = File(dir, "output.pdf")
pdfView.fromBytes(decrepted).load()
} else {
Toast.makeText(this#ViewMedicalRecordActivity, "Failed to load file", Toast.LENGTH_LONG).show()
}
}
Following is the decryption code.
fun decryptFile(symmetricKey: String, file: File): ByteArray {
encryptionAlgorithm = "AES"
encryptionMode = "/ECB"
paddingMode = "/NoPadding"
return decrypt(symmetricKey, file)
}
private fun decrypt(decryptionKey: String, file: File): ByteArray {
val inputStream = BufferedReader(InputStreamReader(FileInputStream(file), Charsets.UTF_16BE))
var x: String? = ""
var builder = StringBuilder()
while (x != null) {
x = inputStream.readLine()
if (x != null)
builder.append(x).append('\n')
}
val text = builder.toString()
val read = text.toByteArray().decrypt(decryptionKey)
val path = Environment.getExternalStorageDirectory().absolutePath + "/folder"
val dir = File(path)
if (!dir.exists())
dir.mkdirs()
val outfile = File(dir, "output.pdf")
val dos = OutputStreamWriter(FileOutputStream(outfile))
dos.write(read.toString(Charsets.UTF_16LE))
dos.flush()
dos.close()
return read
}
//extension function for decrypting the byte array
private fun ByteArray.decrypt(decryptionKey: String): ByteArray {
val secretKeySpec = SecretKeySpec(decryptionKey.toByteArray(), encryptionAlgorithm)
val cipher = Cipher.getInstance(encryptionAlgorithm + encryptionMode + paddingMode)
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec)
return cipher.doFinal(this)
}
As I am new in cryptography I am not really sure where i am going wrong but i think it has something to do with file formats and encoding.
The files get decrypted without any errors but still the following exception is thrown when i try to open file in code or from the file explorer.
E/PDFView: load pdf error
java.io.IOException: cannot create document: File not in PDF format or corrupted.
at com.shockwave.pdfium.PdfiumCore.nativeOpenMemDocument(Native Method)

Saving file in internal storage using Uri (obtained from Storage Access network)

I'm using Storage Access Network to pick file and save in internal storage so that app can use if in future.
I'm getting URI without any issues. It's something like content://com.android.providers.media.documents/document/image%3A141274
Problem comes when I'm trying to save image into internal directory. Code passes without crashes, image with same size is saved into internal directory (I can see it in device Explorer: https://take.ms/3TwBS).
But image itself is broken and can't be opened.
Here's code I'm using (after getting URI)
val destinationFile = File("${context.filesDir.absolutePath}/$fileName")
try {
val writer = FileWriter(destinationFile)
writer.append(readTextFromUri(it))
writer.flush()
writer.close()
} catch (e: Exception) {
e.printStackTrace()
}
#Throws(IOException::class)
private fun readTextFromUri(uri: Uri): String {
val inputStream = activity!!.contentResolver.openInputStream(uri)
val reader = BufferedReader(InputStreamReader(inputStream))
val stringBuilder = StringBuilder()
var line: String? = null
while ({ line = reader.readLine(); line }() != null) {
stringBuilder.append(line)
}
inputStream?.close()
reader.close()
return stringBuilder.toString()
}
As #CommonsWare described I should have used proper dealing with files, not texts.
Proper way to do:
private fun inputStreamToFile(uri: Uri){
val inputStream = contentResolver.openInputStream(uri)
val output = FileOutputStream(File("${filesDir.absoluteFile}/magic.png"))
inputStream?.copyTo(output, 4 * 1024)
}
Or longer way (without extension functions)
fun inputStreamToFile(uri: Uri){
val inputStream = contentResolver.openInputStream(uri)
inputStream.use {
val directory = getDir("test", Context.MODE_PRIVATE)
val file = File(directory, "correct.txt")
val output = FileOutputStream(file)
output.use {
val buffer = ByteArray(4 * 1024) // or other buffer size
var read: Int = inputStream?.read(buffer) ?: -1
while (read != -1) {
output.write(buffer, 0, read)
read = inputStream?.read(buffer) ?: -1
}
output.flush()
}
}
}

Categories

Resources