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)
Related
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() }
}
I have searched everywhere on stackoverflow, there are plenty of similar questions, but the answer always ends up with something that helps write on the internal storage.
I am using the File Browser snippet available here: https://github.com/vaal12/AndroidFileBrowser
After that, I get the path to the directory where I want to create my Folder.
try {
print(Environment.getExternalStorageDirectory().getAbsolutePath()); //return something like "/storage/sdcard0/"
String realPath=newDir +"/"+ getString(R.string.folder_name); //returns something like "/storage/extSdCard/..."
//realPath=realPath.replaceAll("storage", "mnt");
print(realPath);
File f = new File(realPath);
if (!f.exists()) {
f.mkdirs();
}
} catch(Exception e) {
print(e.toString());
}
This works fine when the chosen directory is on the internal sd card, but nothing happens (not even an IOException) when it's on the removable external sd card
There is good description and example about saving onto external storage on the android developer webpage. I think this would help you: http://developer.android.com/guide/topics/data/data-storage.html#filesExternal
I have been trying for the last couple of days to find the right way of writing a file to a subdirectory of the android data folder.
Most answers i found were not clear or didn't address the problem in a right and working way so i finally decided to ask.
I am giving a user the possibility of backing up his data on my server by basically uploading the database to the server through a php script.
The database is located in
'/data/data/com.package/databases/data.db'
The problem here is when a user wants to reload a backed up database.
The application Downloads the file and should then write it (Overwriting the old one) to the /databases/data.db' file, and then reload.
I have managed to get everything to work up until where i have to write the downloaded file because FileOutputStream throws an illegal argument exception saying that i can't use path separators in the path.
I understand that FileOutputStream can only write to the first level of the data folder and not to subdirectories.
How can this be done?
If it can't be done, is there any way to set the default database path to the first level of the 'data' directory to solve this problem?
If this is a completely wrong approach to what i want to obtain i am open to critique but it would still be nice to get an answer, just for future knowing.
public void aSyncDatabaseDownloadFileFinish(PhpWrapper feed) {
if (validateServerResponse(feed.Result)) {
// Copy Database to Directory
try {
FileOutputStream fos = ctx.openFileOutput(ctx.getDatabasePath(DataDatabaseHelper.DBNAME).getAbsolutePath(),
Context.MODE_PRIVATE);
fos.write(feed.DownloadedBytes, 0, feed.DownloadedBytes.length);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
else
Toast.makeText(ctx, ctx.getResources().getString(R.string.nofilesonserver), Toast.LENGTH_SHORT).show();
}
Thanks in advance.
How can this be done?
In your case, use getDatabasePath() to write a file into the standard location for databases for your app.
Regardless of your path separator issue, openFileOutput() will work with files/ directory in your internal storage, not the databases/ directory.
Ok,
I got the answer thanks to Squonk, Still can't believe that it was that simple.
For anybody having the same problem here is an example:
if (validateServerResponse(feed.Result)) {
// Copy Database to Directory
try {
// This Solved the Exception
FileOutputStream fos = new FileOutputStream(ctx.getDatabasePath(DataDatabaseHelper.DBNAME), true);
fos.write(feed.DownloadedBytes, 0, feed.DownloadedBytes.length);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
else
Toast.makeText(ctx, ctx.getResources().getString(R.string.nofilesonserver), Toast.LENGTH_SHORT).show();
Thank you Squonk!
I have a question about Android programming. Basically, I am unsure of where to check where my file is, and if I wrote to it correctly. I want to locate where the file is, and I also want to know whether or not I wrote to it correctly. Below is the code I have come up with:
String lsNow = "testing";
try {
fos = openFileOutput("output.txt", Context.MODE_APPEND);
fos.write(lsNow.getBytes());
fos.close();
}
catch{
...
}
Where can I find output.txt? Might anyone know how to check this all out? if so, that would be great! I am using an emulator by the way. If I were to do this on a real Android, how would one approach this also? (Just for future reference)
You Test it in Two ways
Using File Explorer
Go to DDMS perspective--> Open File Explorer-->location of the file
Pragrammatically by using exits() method
File file = new File(context.getFilesDir(), filename);
if(file.exists())
Using openFileOutput(...) means the file will be written to internal storage on the Android device in an area which is secure from access by other apps.
If you want to make sure the file is written correctly then make sure your catch block handles any failures (if it is called then the file writing has failed).
To access the file once it has been written use openFileInput(...).
My app has .txt files in subdirectories in the assets folder. It reads those .txt files and puts them in a textview. It's working great and no problems.
Should I be concerned about the files in the assets folder getting deleted by the user or missing. If this ever could happen, my app would get an error because the file would not be there when it tried to read it into the stream.
Is there a need for me to check the existence of an asset file before I read it or does the asset manager take care of it all? I also was wondering if there's a chance that a user would or could delete and asset file.
Like I say, everything works fine without me inserting code to check for file existence. I just wondered if people use the .exists() statement every time they go to read in a stream from assets.
You may be concerned that the file have been removed and the apk resigned
You can check using:
Arrays.asList(getResources().getAssets().list("")).contains("myFile")
if you really want to check for the file existence:
AssetManager mg = getResources().getAssets();
InputStream is = null;
try {
is = mg.open(pathInAssets);
//File exists so do something with it
} catch (IOException ex) {
//file does not exist
} finally {
if (is != null) {
is.close();
}
}
If your file is located in assets/folder/file.ext, then pathInAssets would be
"folder/file.ext"
Ideally after apk is built, nobody can remove any assets from it, but if someone decompiled it and recompiles than it may be possible.
Though for other scenarios also when an asset is not present in apk at Runtime, we can check the existence of asset.
In our app, we have a provision to build app using gradle, ant and eclipse, and for each build mechanism some of our assets file are bundled in apk and some are not, so to identify if any asset file is present in current build apk at runtime,
we do this as follows:
private boolean isAssetExists(String pathInAssetsDir){
AssetManager assetManager = AppContext.get().getResources().getAssets();
InputStream inputStream = null;
try {
inputStream = assetManager.open(pathInAssetsDir);
if(null != inputStream ) {
return true;
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
Yes and No.
A normal user would not be able to delete them, but a user on a rooted phone who doesn't know what they're doing… that's a different situation.
If you ask me, the extra code is not needed. Also if you try and open a file that doesn't exist, you will get an exception thrown at some point, catch that and display a dialog if you really want to.
AssetManager am = getAssets();
try {
List<String> mapList = Arrays.asList(am.list("path/in/assets/folder"));
if (mapList.contains("file_to_check")) {
Log.e("ERROR", "exists");
} else {
Log.e("ERROR", "not exists");
}
} catch ( IOException ex){
ex.printStackTrace();
}
Convert to function or method can be easy ;)
I think you should be OK. From having a root around in my phone I can't see any way of deleting the assests without deleting the app as it all seems to be wrapped up in the .apk file. You can do it but I think you need to be rooted or use adb.
I would personally surround any reading/writing with a try/catch block anyway, just to be safe.