How to get File object from assets? - android

I have a markdown file in my assets folder. I am using a markdown viewer which takes java.io.File Object as an argument to parse the file on screen.
But i don't know how to get a File Object from a file in assets folder.
Is there a way i can achieve this. I tried URI way but it failed.
This is my code snippet which may help
val markDown = File("file:///asset/GalacticAstronomy.md")
if (markDown.exists()) {
Toast.makeText(baseContext, "File exist", Toast.LENGTH_SHORT).show()
} else Toast
.makeText(baseContext, "File doesn't exist", Toast.LENGTH_SHORT).show()
setContent {
MaterialTheme {
MarkDown(
file = markDown,
modifier = Modifier.fillMaxSize()
)
}
}
I am not trying to read the file, So using assets.open("file") isn't going to work

But i don't know how to get a File Object from a file in assets folder
That is not possible, as it is not a file.
I am not trying to read the file, So using assets.open("file") isn't going to work
You do not have a choice. Either:
Use a better markdown library, one that accepts an InputStream, or
Copy the asset to a file yourself (e.g., in getCacheDir()) using assets.open()), then use the resulting file with your existing library

Related

Android Studio: Creating a File Object for Directory in Project Resource Folder

I have a folder full of images and videos in my RAW directory. I want to turn this folder into a file object in Kotlin, then traverse all the folders and files within and convert them into media that's usable for my app.
The directory that contains my media (I want to convert this into a file object, this is the issue I am having):
val basePath = Paths.get("").toAbsolutePath().toString()
traverse(db, File("$basePath/app/src/main/res/raw/media1")) // This is a directory, and it's not being seen using this code.
My traverse() method iterates through the media1 directory and converts all found images/videos to usable media for my app.
fun traverse(db: SQLiteDatabase?, dir : File) {
if (dir.exists()) {
val files = dir.listFiles()
if (files != null) {
for (i in 0 until files.count()) {
val file = files[i]
if (file.isDirectory) {
traverse(db, file)
} else {
saveFile(db, file) // This fun creates a database row for the media and saves the media file onto the local phone for later reference
}
}
}
}
}
I tried accessing the directory through the C drive, through the Paths.get command, calling R.raw. No matter what, it seems to not see the "media1" directory...
I want to turn this folder into a file object in Kotlin, then traverse all the folders and files within and convert them into media that's usable for my app.
Sorry, that is not an option. You will be far better served moving this set of directories into assets/ rather than raw/, then use AssetManager to traverse the tree. However, even then, you do not get files, but rather InputStreams, because neither assets nor resources are files on the phone's filesystem.
No matter what, it seems to not see the "media1" directory
Partly, that is because they are not files on the phone. Partly, that is because resources do not support subdirectories.
This ended up being my solution:
val fields : Array<Field> = R.raw::class.java.fields
for (count in 0 until fields.count()) {
val resourceID = fields[count].getInt(fields[count])
val value = TypedValue()
context!!.resources.getValue(resourceID, value, true)
val inputStream: InputStream = context.resources.openRawResource(resourceID)
val file : File = createTempFile(fields[count].name, '.' + value.string.toString().split('.')[1])
inputStream.use {input ->
file.outputStream().use {output ->
input.copyTo(output)
}
}
saveFile(db, file)
}
The individual media files were moved from their sub-directories and into the raw resource folder of the project.
Android studio doesn't let you traverse sub-directories, and resources must be manually loaded into File objects using input and output streams. I find it ridiculous that we have to jump through so many hoops to accomplish something so basic.

Unable to create folder in internal directory

I am trying to create folder in Android internal storage. For that I am using below code
val path = File(getExternalFilesDir(null),"MyFolder")
But it is creating folder in Android directory inside app package name under files directory like this: Android/data/com.app.myapp/files/MyFolder. I don't want to create folder like this rather I want to create folder in internal storage like WhatsApp creates.
How can I do this?
So easy, for API level 29 or later:
binding.createFolderButton.setOnClickListener {
val values = ContentValues()
values.put(MediaStore.MediaColumns.RELATIVE_PATH, "${Environment.DIRECTORY_DOCUMENTS}/myFolder/") //folder name
contentResolver.insert(MediaStore.Files.getContentUri("external"), values)
Toast.makeText(this, "\"myFolder\" created", Toast.LENGTH_SHORT).show()
}
Demo: https://youtu.be/a6Q7IlA_uOs
Helpful video: https://youtu.be/UnJ3amzJM94

How to read from path to media file that located under raw dir (native)?

I have native JNI implementation and for now I have my media files under the app dir /storage/emulated/0/Android/data/com.my_app.debug/files/Models/my_media_file.mp4 in order to start read one of the files I need to pass a path to JNI where inside I use such method that expect to get path_to_mp4_file
bool Decoder::InitFromFile(std::string const &filename)
{
m_file.open(filename, std::ios::binary);
if (!m_file.is_open())
{
return false;
}
...
}
And all works, but now I need to read from build-in raw folder, so now in order to get path to my file I am using this way
fun foo()
{
...
val path = "android.resource://" + activity!!.packageName + "/" + R.raw.my_media_file
val uri = Uri.parse(path)
JNIImplementation.InitFromFile(uri.path)
...
}
But now uri = android.resource://com.my_app.debug/2131492865 if I get uri.path = /2131492865.
Issue is that if I pass this uri.path as a path to InitFromFile method I get an error, because I can't open file by path /2131492865.
So, as far as I understand there is should be a way to read from raw or assert folder native way or something like this
How to do it?
Or maybe there is a way how to put this media file in app (build-in) and have access to get path as to regular file? I mean somehow look at this file not as a resource, but as a simple file?

Kotlin: How to create/append file (and share)

I have a list of arrays of data in my app that I would now like to write to a file (csv) and use a 3rd party app (such as email) to share this csv file. I have had no luck finding any helpful resources for creating, finding the file path for, and appending to a file in Kotlin. Does anyone have experience with this or have examples to point to? Just to get started I'm trying to write the header and close the file so I can see that it is correctly writing.
This is what I have for now:
val HEADER = "ID, time, PSI1, PSI2, PSI3, speed1, speed2, temp1, temp2"
val filename = "export.csv"
var fileOutStream : FileOutputStream = openFileOutput(filename,Context.MODE_PRIVATE)
try {
fileOutStream.write(HEADER.toByteArray())
fileOutStream.close()
}catch(e: Exception){
Log.i("TAG", e.toString())
}
It doesn't throw the exception, but I cannot find the file in the file system. I'm using a physical tablet for testing/debug. I've checked the com.... folder for my app.
I cannot find the file in the file system
Use Android Studio's Device File Explorer and look in /data/data/.../files/, where ... is your application ID.
Also, you can write your code a bit more concisely as:
try {
PrintWriter(openFileOutput(filename,Context.MODE_PRIVATE)).use {
it.println(HEADER)
}
} catch(e: Exception) {
Log.e("TAG", e.toString())
}
use() will automatically close the PrintWriter, and PrintWriter gives you a more natural API for writing out text.
It appears there are many ways to create a file and append to it, depending on the minimum API version you are developing for. I am using minimum Android API 22. The code to create/append a file is below:
val HEADER = "DATE,NAME,AMOUNT_DUE,AMOUNT_PAID"
var filename = "export.csv"
var path = getExternalFilesDir(null) //get file directory for this package
//(Android/data/.../files | ... is your app package)
//create fileOut object
var fileOut = File(path, filename)
//delete any file object with path and filename that already exists
fileOut.delete()
//create a new file
fileOut.createNewFile()
//append the header and a newline
fileOut.appendText(HEADER)
fileOut.appendText("\n")
/*
write other data to file
*/
openFileOutput() creates a private file, likely inside of app storage. These files are not browsable by default. If you want to create a file that can be browsed to, you'll need the WRITE_EXTERNAL_STORAGE permission, and will want to create files into a directory such as is provided by getExternalFilesDir()

How to create a text file and write to it in Kotlin?

I am new to Kotlin/Android development. I am trying to simply write text to a text file. I simply cannot figure out how to do this. I have tried doing:
File("filename.txt").printWriter().use { out ->
out.println("${it.key}, ${it.value}")
}
And I got the following. (Side note, "filename.txt" is located in the assets folder in my project)
Caused by: java.io.FileNotFoundException: prices.txt (Read-only file system)
So I figured out that I need to be writing to a spot where I have permission. To my knowledge this is internal private storage. I figured out which directory I have permissions to write to by using:
filesDir
That gave me:
/data/user/com.example.myname.appname/files
So from what I have seen so far I just need to create a file in this directory, write to said file, and read from it when I would like. The problem is I don't know how to do that. But I tried doing this:
// create file?
val file = File(applicationContext.filesDir, "test.txt")
//try to write to said file?
applicationContext.openFileOutput(file.toString(), Context.MODE_PRIVATE).use
{
it.write("test".toByteArray())
}
But then I get this error:
Caused by: java.lang.IllegalArgumentException: File
/data/user/0/com.example.pawlaczykm.dollarsense/files/test.txt contains
a path separator
I am at the point of maximum misunderstanding and confusion. Again, my goal is to write something to a text file, then access the file later throughout the application.
Update
Tried the following and didn't see back "comment":
File(applicationContext.filesDir, "test.txt").printWriter().use{ out ->
out.println("content")
}
File(applicationContext.filesDir, "test.txt").bufferedReader().use{ out ->
var text5 = out.toString()
Toast.makeText(this, text5.toString(), Toast.LENGTH_LONG).show()
}
openFileOutput() takes a filename, not a path. openFileOutput() returns an OutputStream on a file that is located in the directory identified by getFilesDir() (a.k.a., filesDir in Kotlin).
Try:
File(applicationContext.filesDir, "test.txt").printWriter().use { out ->
out.println("${it.key}, ${it.value}")
}
or:
applicationContext.openFileOutput("test.txt", Context.MODE_PRIVATE).use
{
it.write("test".toByteArray())
}

Categories

Resources