I use the following function to write a long string (byte array size is 871504) to the internal storage of an Android device, but it takes around one and a half minute to complete. However, for another string (byte array size is 782979), it just takes a few seconds to complete.
fun saveTempSrc(data: String, ctx: Context) {
try {
val dataByteArray = data.toByteArray()
Timber.d("saveTempSrc: byte array size = %d", dataByteArray.size)
val inputStream = BufferedInputStream(ByteArrayInputStream(dataByteArray))
val outputStream = BufferedOutputStream(ctx.openFileOutput("example.txt", Context.MODE_PRIVATE))
inputStream.copyTo(outputStream)
inputStream.close()
outputStream.flush()
outputStream.close()
} catch (e: IOException) {
Timber.e(e, "Write Temp file failed")
}
}
Is this function suitable for writing long string to file? I run this function in RxJava's I/O scheduler.
Try to use FileWriter.
val sdcard = ctx.getExternalStorageDirectory()
val file = File("example.txt", sdcard)
val fileWriter = FileWriter(file)
fileWriter.write(data)
fileWriter.flush()
fileWriter.close()
Sorry that the long waiting time is not due to file I/O but due to Regex find with a very long string before writing file.
Related
I am getting some audio streaming data as base64 String, I convert it in byteArray and then write a file locally as mp3 file to play in mediaplayer. But the problem is mediaplayer througing error(1,-2147483648). How to solve this, I tried with many SO posts but nothing works.
**what I am trying to do is fetch base64 string save locally and play**.
val file = requireContext().getExternalFilesDir(null)?.absolutePath + "/audioRecording1.mp3"
val mediaPlayer = MediaPlayer()
try {
val output = FileOutputStream(file)
output.write(mp3SoundByteArray)
output.close()
val fis = FileInputStream(file)
mediaPlayer.setDataSource(fis.fd)
fis.close()
mediaPlayer.setAudioAttributes(
AudioAttributes.Builder().
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).
setUsage(AudioAttributes.USAGE_MEDIA).
build())
mediaPlayer.prepareAsync()
mediaPlayer.setOnPreparedListener {
mediaPlayer.start()
}
mediaPlayer.setOnErrorListener { mediaPlayer, i, i2 ->
Log.v("","${i,i2}")
true
}
}catch (e:Exception){
toast(e.message!!)
}
could you please tell me how to overcome this?
I am not sure, but it seams that you have trouble with file saving
fun saveFile(responseBody: ResponseBody?, pathWhereYouWantToSaveFile: String) {
val body = responseBody ?: return
var input: InputStream? = null
try {
val uri = Uri.parse(pathWhereYouWantToSaveFile)
input = body.byteStream()
val parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, FileConst.WRITE_MODE)
val fileOutputStream = FileOutputStream(parcelFileDescriptor?.fileDescriptor)
fileOutputStream.use { output ->
val bufferSize = BUFFER_SIZE.toInt()
val buffer = ByteArray(bufferSize)
var read: Int
while (input.read(buffer).also { read = it } != END_OF_FILE) {
output.write(buffer, START_OFFSET, read)
}
output.flush()
}
} catch (exception: Exception) {
logErrorIfDebug(exception)
} finally {
input?.close()
}
}
const val READ_MODE = "r"
const val WRITE_MODE = "w"
const val START_OFFSET = 0
const val END_OF_FILE = -1
const val BUFFER_SIZE = 4 * BYTES_IN_KILOBYTE
Try this in your viewModel or data sourse layer, then send result to UI layer and use there
Have you checked that your file saved correct? You can go to directory and try to open file. If everything okey, you can get it by uri in your media player.
Also you should check - perhaps you are creating another path for save and retrieve
Better way to use player is https://exoplayer.dev/
But native library also can work with internal uri path.
If you just take a random part of a base64 encoded audio stream then your bytearray will (after decoding) contain a part of an audiofile.
Some audio stream bytes.
Not a complete valid mp3 file with headers and such.
If you had said: am getting a mp3 file in one base64 String then your approch would be ok.
I have solved the issue without writing any header. below way.
val clipData =android.util.Base64.decode(data,0)
val output = FileOutputStream(file,true)
output.write(clipData)
output.close()
I tried many times to save recorded audio to internal storage but I got exception
Caused by: java.io.FileNotFoundException: /data/user/0/sepahtan.sepahtan/files/sound/1653658919164.3gp: open failed: ENOENT (No such file or directory)
private fun getFileName(): String {
val path = requireContext().filesDir.path
val file = File(path,"sound")
try {
file.mkdirs()
}catch (e:Exception){}
return "$file/${System.currentTimeMillis()}.3gp"
}
This function giving me path and i put it into
mediaPlayer.setDataSource(getFileName())
I already studied all question about this title
The function you need is actually like this:
fun saveRecordedAudio(inputStream: InputStream) {
val outputStream: OutputStream = FileOutputStream(getFileName())
val buffer = ByteArray(1024)
var read: Int
var total: Long = 0
while (inputStream.read(buffer).also { read = it } != -1) {
outputStream.write(buffer, 0, read)
total += read.toLong()
}
inputStream.close()
outputStream.close()
}
Before mediaPlayer.setDataSource(getFileName()), Actually you need to get inputStream of your recorded file and save it into internal storage using above function.
You can record the audio using AudioRecord API from the Android SDK package.
Note that saving to storage may be a challenge for different Android versions.
For storing two-dimensional integer data (matrix) during the life of an application, it takes only one line of code (int myArray[][] = new int[][]) to store this data within the activity, and a relatively simple procedure (like for any other type of variable) using "intent" for transfer between activities.
However, if you want to store exactly the same data outside the runtime of the application, all the solutions that have been offered (for which I'm grateful) involve dozens of code lines.
Does anyone have a simple solution (I mean, as simple a the transfer between activities, or as simple as saving a string variable to SavedPreferences) for saving matrices outside application runtime?
You basically just need to convert the 2D array into a string and then store it in a file. Something along the following lines should work as you require.
private fun writeFileOnInternalStorage(context: Context, sFileName: String, sBody: Array<IntArray>) {
val file = File(context.getFilesDir(), "mydir")
if (!file.exists()) {
file.mkdir()
}
try {
val gpxfile = File(file, sFileName)
val writer = FileWriter(gpxfile)
writer.append(sBody.map {
//Convert the array to string using separators
it.joinToString(separator = ",")
}.joinToString(separator = "|"))
writer.flush()
writer.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun readFileOnInternalStorage(context: Context, sFileName: String): Array<IntArray> {
var result = emptyArray<IntArray>()
val file = File(context.getFilesDir(), "mydir")
if (!file.exists()) {
return result
}
try {
val gpxfile = File(file, sFileName)
val reader = FileReader(gpxfile)
val content = reader.readText()
//Convert the string back into a 2D array using the separators
result = content.split("|").map {
it.split(",").map {
Integer.parseInt(it)
}.toIntArray()
}.toTypedArray()
reader.close()
} catch (e: Exception) {
e.printStackTrace()
}
return result
}
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()
}
}
}
I have written a c# web service that returns a pdf in a stream of bytes as response. Once I make a call to the web-service from my android app, I will store the response in an array byte till here I will be able to do it. But after that I need to convert that byte array into pdf, I should be able to display that. I have a menu page in which once the button is pressed the call is made to the web service with file name and on click of button I should be able to open pdf. Is this possible? Or there is some other, better solution? I checked on the net for better understanding, but I was unable to find one that could help me understand better.
Thanks for the suggestion, but I don't have the pdf in hand, I just have the array bytes, which I got from the web service. So I now need to regenerate the pdf from this array of bytes and display it, but I am not getting how to do it.
Try following these steps
Convert byte array to InputStream
val inputStream = ByteArrayInputStream(byteArray)
Save InputStream as PDF file:
suspend fun saveInputStreamAsPdfFile(inputStream: InputStream, applicationContext: Context): File? {
var outputFile: File? = null
withContext(Dispatchers.IO) {
try {
val directory = ContextCompat.getExternalFilesDirs(applicationContext, "documents").first()
val outputDir = File(directory, "outputPath")
outputFile = File(outputDir, UUID.randomUUID().toString() + ".pdf")
if (!outputDir.exists()) {
outputDir.mkdirs()
}
val outputStream = FileOutputStream(outputFile, false)
inputStream.use { fileOut -> fileOut.copyTo(outputStream) }
outputStream.close()
} catch (e: Exception) {
// Something went wrong
}
}
return outputFile
}
Show PDF with PdfRenderer
var totalPdfPages: Int
fun showPdf(pdfFile: File) {
val input = ParcelFileDescriptor.open(pdfFile, MODE_READ_ONLY)
val renderer = PdfRenderer(input)
val wrapper = PdfRendererWrapper(renderer)
totalPdfPages = wrapper.getTotalPages()
showPdfPage(0)
}
fun showPdfPage(currentPageIndex: Int) {
val pageBitmap = wrapper.getBitmap(currentPageIndex)
imageView.setImageBitmap(pageBitmap) // Show current page
}