I have placed a file in my Tablet\Tablet\Android\data\my.app.package\files\data called test.txt with a few lines of text. This is reported by Windows.
Kotlin is throwing an Exception (FileNotFound) and I have also tried specifying what I believe is the real path of the file, but cannot seem to get it using the following path:
"/0/Android/data/my.app.package/files/data/test.txt" (my app's data directory). This directory definitely exists as I can see it in device file managr.
This file contains 2 lines of text, which I am trying to read in to run specific tasks based on their values. I've tried with a BufferedReader, but I'm getting FileNotFound Exception...
This is my code:
fun readFile() {
val yourFilePath = "/0/Android/data/my.app.package/files/data/test.txt"
val yourFile = File(yourFilePath)
print(yourFile.name)
val file = File(yourFilePath)
file.bufferedReader().forEachLine {
println("value = $it")
}
}
Any help is highly appreciated. Thankyou!
filesDir for pointing to the internal storage files directory
use blocks are good when you want to close stream automatically.
try-catch block to handle any IO exceptions, e.g. FileNotFoundException.
try {
val file = File(filesDir, "test.txt")
if (file.exists()) {
file.bufferedReader().useLines {
...
}
}
} catch (e: IOException) {
...
}
Great article for a more in-depth look: Medium
Make sure your file exists by looking at your internal storage by:
AndroidStudio -> View -> Tools Windows -> Android Device Explorer
context.openFileInput(fileName).use { stream ->
stream.bufferedReader().use { it.readText() }
}
Related
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.
This is my code so far, supposedly this helps generate a file but I can't find it anywhere. I believe that's becuase there isn't a file path or directory provided. So what should I add to properly set the path?
fun generateFile(){
val fileName = "dataFile.txt"
try {
val fos = openFileOutput(fileName, MODE_PRIVATE)
val data: String = binding.text.toString()
fos.write(data.toByteArray())
fos.flush()
fos.close()
} catch (e: IOException) {
e.printStackTrace()
}
binding.text.setText("")
Toast.makeText(applicationContext,"writing to file " + fileName.toString() + "completed...",Toast.LENGTH_SHORT).show()
}
I believe that's becuase there isn't a file path or directory provided
There is one implied by openFileOutput(). That puts the file into the directory referred to by getFilesDir() on Context.
but I can't find it anywhere
That location is part of internal storage. That file is accessible by your app, but not by users. On debug builds of your app, you can get it via tools like Android Studio's Device File Explorer.
Hy
I noticed that, Environment.getExternalStoragePublicDirectory() is deprecated, and after that I read a lot, and I found a tip, that I should use MediaStore.
So, a searched, but I didn't found, how can I get a downloaded .apk file.
Previously, I read the file like this from the Download folder, but in Android 10 I get a access denied exception
val existingFileMd5 = try {
File(
Environment.getExternalStoragePublicDirectory(INSTALLER_PATH),
INSTALLER_NAME
).md5()
} catch (e: Exception) {
Timber.e(e)
null
}
Can someone help me, how to use MediaStore in a similar way?
I solved it by using the private storage of the application.
application.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
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()
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())
}