I'm downloading some text data by issuing a HTTP GET request to server. I want to save downloaded text file to re-use it on request if it has already been downloaded. But I want to keep my data private, so that no other apps could access it. On the other hand, it would be OK if Android removed that files if there's not enough disk space.
So, my question is - should I store downloaded content in App Data folder or in cache folder? Is there any difference between two?
First, I used to save files in App Data folder, using a method like
public void save(String fileName, String data) {
FileOutputStream fos;
try {
fos = mContext.openFileOutput(fileName, Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Using this method I can set Private mode for my files so that no other apps could access them. But then I thought about moving files to cache directory, I need to do something like
private void save(String filename, String data) {
File cacheDir = new File(mContext.getCacheDir(), "app_directory");
cacheDir.mkdir();
try {
FileOutputStream fos = new FileOutputStream(new File(cacheDir, filename));
fos.write(data.getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I cannot set Private attribute to my files anymore, so, as I understand, any application will be able to get access to my data. Am I right?
Maybe there's a way to make files in cache directory private? Or it doesn't really matter where to save files to?
Both the CacheDir and the FilesDir are app specific, and can not be accessed by any other app.
Both of these however can be accessed if the user has rooted their device.
The CacheDir is for temp files, that may be deleted if so required to free up space by Android OS. The Files dir will not be cleared unless explicitly done so by the app, the user, or if the app is uninstalled.
This is covered in the docs:
http://developer.android.com/guide/topics/data/data-storage.html
Saving cache files
If you'd like to cache some data, rather than store it persistently,
you should use getCacheDir() to open a File that represents the
internal directory where your application should save temporary cache
files.
When the device is low on internal storage space, Android may delete
these cache files to recover space. However, you should not rely on
the system to clean up these files for you. You should always maintain
the cache files yourself and stay within a reasonable limit of space
consumed, such as 1MB. When the user uninstalls your application,
these files are removed.
Data in the cache can only be accessed your app (if its not rooted, but thats a user choice to minimze security)
Related
I have created an android app that gets input from user through EditText and writes them to name.txt file in phone's internal storage. Is it possible to open the text file in phone's file manager? I tried to get the file path using getFilesDir().getAbsolutePath()+"/"+FILE_NAME. But couldn't locate the file in file manager.
You need to use External storage if you want another app like File Manager to access the file. Internal storage is only readable by your app.
In the comments you ask a valid question - "What if the phone doesnt have external storage...?". That is not really a concern today. See https://developer.android.com/training/data-storage/files:
Many devices now divide the permanent storage space into separate
"internal" and "external" partitions. So even without a removable
storage medium, these two storage spaces always exist...
==========
So change your above code to this:
getExternalFilesDir().getAbsolutePath()+"/"+FILE_NAME
getExternalFilesDir is a method from the android.content.Context class. So this call will work from your activity class which is a Context.
=============
Further supporting the choice of external storage is the following, also from https://developer.android.com/training/data-storage/files.
Internal storage is best when you want to be sure that neither the
user nor other apps can access your files.
External storage is the best place for files that don't require access
restrictions and for files that you want to share with other apps or
allow the user to access with a computer.
there is private storage for each app that can be accessed from the app itself and then public storage /sdcard/... that other app can access too (it needs to get Storage Permission from system)
this method will save a content in a file in private storage of app
public void saveFile(String fileName, String content) {
try {
FileOutputStream fOut = context.openFileOutput(fileName, Context.MODE_PRIVATE);
fOut.write((content).getBytes());
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
}
So I am aware that there is SD Card access API which allows us to write files via DocumentProvider and DocumentFiles. I have made it work on removable SD Cards. I was always confused about External and Internal Storage. I always thought External Storage is Always SD card but today I came to know that it is not so.
So I have three question .
Question1 , how to know if Files are stored in external emulated storage or sdcard ?
One solution maybe by searching for instances of "sdcard0" or "emulated" in the file path.
Will this solution always work? I mean on all phones?
Question 2 what to Use for writing files on emulated storage(non removable external storage) normal files or DocumentFile?
Question 3 If solution of Q2 is Document File then why doesn't this work ?
private static String[] getExtSdCardPaths() {
List paths = new ArrayList<>();
for (File file : GlobalSongList.GetInstance().getApplicationContext().getExternalFilesDirs("external")) {
if (file != null && !file.equals(GlobalSongList.GetInstance().getApplicationContext().getExternalFilesDir("external"))) {
int index = file.getAbsolutePath().lastIndexOf("/Android/data");
if (index < 0) {
Log.w("StorageAccessAPI", "Unexpected external file dir: " + file.getAbsolutePath());
}
else {
String path = file.getAbsolutePath().substring(0, index);
try {
path = new File(path).getCanonicalPath();
}
catch (IOException e) {
// Keep non-canonical path.
}
paths.add(path);
}
}
}
return paths.toArray(new String[paths.size()]);
}
So I am aware that there is SD Card access API which allows us to write files via DocumentProvider and DocumentFiles.
You are referring to the Storage Access Framework. This allows you to read and write streams, not files, where the streams are backed by document providers. The user chooses what document provider to use, which in turn determines where the stream's content is stored. That could be local (e.g., external storage, removable storage) or remote (Google Drive, Dropbox, Samba file server, Web server, FTP server, SFTP server, etc.).
how to know if Files are stored in external emulated storage or sdcard ?
If you are using the Storage Access Framework, you do not know where the stream's content is stored.
what to Use for writing files on emulated storage(non removable external storage) normal files or DocumentFile?
If you explicitly want to use external storage, use external storage.
Using the Storage Access Framework allows the user to choose where the stream's content is stored, which may or may not be external storage.
why doesn't this work ?
I have no idea what you expect that to do. I expect it to return a series of useless strings.
I've faced one problem. I want to store a certain folder with media data here /data/data/com.package.name using Context.getExternalFilesDirs. But i want to hide the data from users. But everyone can get this files from /data/data/com.package.name folder. Even if the files are hidden, still people with rooted devices can access this data. So i need some way to encrypt or zip the folder to protect it. How can i protect the folder?
Can i use Zip with password? Is it safe?
I think it's not good practice to encrypt all binary files and decrypt them because it will take a lot of time.
There is no way to prevent user from accessing these files. If user wants them he or she can extract password from your app and decrypt zip archive.
When passwords are on your server then files can't be decrypted, but when your app downloads password to decrypt data then user can sniff that password.
If you want to store data that no one should ever access (e.g. passwords) I'm afraid that you should read about Security Through Obscurity
Basically when your application can decrypt data, advanced user can do it too.
For normal users (with non-rooted phone) storing files in /data/data/ are not accessible. But with rooted phone there is no way to stop users from getting what they want.
I found the solution. Very nice java library http://www.lingala.net/zip4j/
does the work: here is an example
public void unzipFile(){
String path= Environment.getExternalStorageDirectory().getAbsolutePath();
String source = path+"/Download/circus.zip";
String destination = path+"/Download/";
String password = "1234567";
try {
ZipFile zipFile = new ZipFile(source);
if (zipFile.isEncrypted()) {
zipFile.setPassword(password);
}
zipFile.extractAll(destination);
} catch (ZipException e) {
e.printStackTrace();
}
}
I want to store data on external storage and Environment.getExternalStorageDirectory() returns /storage/emulated/0/
path and and when i store data on that directory it store data on storage/sdcard0/... and on /storage/emulated/0/
I need to store a great numbers of images on external storage
How could i implement that?How could i get path on external storage?
How could I get path on external storage?
/storage/emulated/0/ and storage/sdcard0/ is basically the same, this is just an alias. On devices like the Nexus 5 and any other device that doesn't have a physical SD card, "external storage" means the device built-in storage which emulates an SD card. Environment.getExternalStorageDirectory() will point to this location so you are good to go using this method.
From the docs:
Note: don't be confused by the word "external" here. This directory
can better be thought as media/shared storage. It is a filesystem that
can hold a relatively large amount of data and that is shared across
all applications (does not enforce permissions). Traditionally this is
an SD card, but it may also be implemented as built-in storage in a
device that is distinct from the protected internal storage and can be
mounted as a filesystem on a computer.
First of all find of path of external storage
String path = Environment.getExternalStorageDirectory().toString() + directoryName;
then you can write whatever content you want to the file as follows:
File file = new File(path, fileName);
BufferedWriter br;
try {
br = new BufferedWriter(new FileWriter(file));
br.write(content);
br.close();
} catch (IOException e) {
e.printStackTrace();
}
In my task i need to read and write the file in Raw folder. I did the first one to read the file from my project, Now i want to Write the same file. So it easy for me to make any update in that file.
On Seeing this How to write files to assets folder or raw folder in android?
I allow the user to set password ie writing the pass into the file then read the pass and validate if it matches. Is it possible to Write file in Raw Folder
Any data present in the "res" folder is not writable. You can only read data from it. You can never write data to res folder on the fly. If you are looking for a way to store username and password credentials, you can make use of Shared Prefrence
Here is an example on how to use it.
http://marakana.com/forums/android/examples/63.html
Edit 1
Storing data in Shared Preference is persistent unless user clears the data using "clear data" button in your settings page.Navigate to settings->manage apps->your app. Here you will be seeing uninstall button and clear data button. And one more thing in android is you will never be able to save a persistent data. You can't use any data storage methods like preference, sqlite or file system to store a data for permanent. If user wants to wipe the data he clicks on "Clear Data" button and your data are gone. So you have make your coding in such a way to handle this.
Since this is not possible, you could try to use your app's resources which is write protected and not possible to write to it. So it depends on user or you might have to use your server to store the data over there.
No,it's not possible to write file in raw folder
you should use shared prefrence for that.
http://samir-mangroliya.blogspot.in/p/android-shared-preferences.html
Yes, it cannot be done. Instead of trying to write in raw directory, Update your files in the local file system by using Shared Preferences as described in below link :
Please refer http://developer.android.com/guide/topics/data/data-storage.html#filesInternal.
Any data present in the "res" folder is not writable. You can only read data from it.
See this tutorial from the Android Dev site :
http://developer.android.com/training/basics/data-storage/files.html
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}