“This is the first day of my participation in the First Challenge 2022. For details: First Challenge 2022”
1. Data storage concept
Android provides a variety of options for saving application data:
- File storage:
- Application-specific file storage:
- Internal storage (storing sensitive information that should not be accessed by other applications)
- External storage
- Shared file store: Stores files that your application intends to share with other applications, including media, documents, and other files.
- Application-specific file storage:
- Preferences: By default, Preferences use SharedPreferences to save values.
- Database: Use the Room persistence library to store structured data in a private database.
Transient data: Data stored in memory that could be lost if a program is shut down or memory is reclaimed for other reasons.
Data persistence: The preservation of instantaneous data in memory to a storage device, ensuring that the data will not be lost even if the phone or computer is turned off. Persistence technology provides a mechanism for data to be switched between homeopathic and persistent states.
Application-specific file storage
File storage is one of the most basic data storage methods in Android. It does not format the stored content. All data is stored in files intact, so it is more suitable for storing some simple text data or binary data.
Access method:
-
Internal Storage,
- getFilesDir()
- getCacheDir()
-
External Storage
- getExternalFilesDir()
- getExternalCacheDir()
Note: When uninstalling the application, all files in the directory will be removed. And other applications cannot access these exclusive files.
Required permissions:
-
Internal storage is never needed
-
External storage is not required when your app is running Android 4.4(API level >=19) (currently compatible with basic 5.0).
2.1 Accessing persistent Files
You can access this directory using the filesDir property of the Context object.
//From internal storage, getFilesDir() or getCacheDir()
File filesDir = getFilesDir();// Persist file directory
/ / FilesDir: / data/user / 0 / com. SCC. Datastorage/files
Log.e("File"."FilesDir:"+filesDir.getAbsolutePath());
File cacheDir = getCacheDir();// Cache file directory
/ / CacheDir: / data/user / 0 / com. SCC. Datastorage/cache
Log.e("File"."CacheDir:"+cacheDir.getAbsolutePath());
Copy the code
Com.sc. datastorage: represents the name of your package.
Note: To help maintain application performance, do not open and close the same file multiple times.
2.2 Storing Data in a File
The Context class provides an openFileOutput() method that can be used to store data to the specified text.
This method takes two arguments:
- The first parameter is the file nameNote that the file name specified here cannot contain a path (because the default is stored to
/data/data/<packagename>/files/
Directory). - The second parameter is the mode of operation of the file. There are two main types:
-
- MODE_PRIVATE: the default operation mode. When the same file name is specified, if the file name has content, the call will overwrite the original content.
-
- MODE_APPEND: appends to the file if it already exists.
Call openFileOutput() to get the FileOutputStream. Once you get the FileOutputStream, you can write data to the file as a Java stream.
public void write(a){
/ / file name
String filename = "sccFile";
// Write content (shuaici)
String fileContents = fileStorageBinding.etInput.getText().toString();
// The content cannot be empty
if (fileContents.isEmpty()) {
Log.e("File"."FileContents.isEmpty()");
return;
}
BufferedWriter writer = null;
try {
// Get the FileOutputStream object
FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE);
// Build a BufferedWriter object from OutputStreamWriter
writer = new BufferedWriter(new OutputStreamWriter(fos));
// Write the text content to the file through the BufferedWriter object
writer.write(fileContents);
}catch (IOException e){
Log.e("File",e.getMessage());
}finally {
try {
// Manually close the input stream regardless of whether an exception is thrown
if(writer ! =null) writer.close();
} catch(IOException e) { e.printStackTrace(); }}}Copy the code
Change the second parameter to MODE_APPEND if you want to write multiple entries to the same file
out = openFileOutput("data", Context.MODE_PRIVATE);
Copy the code
The contents are stored for 3 times (ANDROID, Shuaici, 123456) as follows:
2.3 Reading Data from a File
// Read the file
public void read(a){
Log.e("File"."read.start");
String filename = "sccFile";
BufferedReader reader = null;
try {
// Get the FileInputStream object
FileInputStream fis = openFileInput(filename);
// Build a BufferedReader object from InputStreamReader
reader = new BufferedReader(new InputStreamReader(fis));
StringBuilder sb = new StringBuilder();
String line = "";
// Reads the data line by line, terminating the loop when the data is empty
while((line=reader.readLine())! =null){
sb.append(line);// Add data to StringBuilder
}
Log.e("File",sb.toString());
fileStorageBinding.etInput.setText(sb.toString());
}catch (IOException e){
Log.e("File",e.getMessage());
}finally {
Log.e("File"."read.finally");
try {
if(reader ! =null) reader.close();
} catch(IOException e) { e.printStackTrace(); }}}Copy the code
Note: If you need to stream files during installation, save the files in the project’s /res/raw directory. You can open these files using openRawResource(), passing in the file name prefixed with R.raw as the resource ID. This method returns an InputStream that can be used to read the file. You cannot write to the original file.
2.4 Viewing the File List
You can call fileList() to get an array containing the names of all files in the filesDir directory, as follows:
// View the file list
public void filelist(a){
String [] files = fileList();
for (String file : files) {
Log.e("File"."The FileList."+file); }}Copy the code
2.5 Deleting a File
-
The easiest way to delete a file is to have the open file reference itself call delete().
-
If the file is in internal storage, you can also delete the file by calling deleteFile().
// Delete files
public void delete(a){
String filename = fileStorageBinding.etInput.getText().toString();
Log.e("File"."Delete:"+deleteFile(filename));
filelist();
}
Copy the code
Note: When a user uninstalls your application, the Android system will delete all files saved in internal and external storage. Of course, you can also periodically delete the cache files you create that you don’t need.
3. Cache files (cache directory)
3.1 Creating a Cache File
If you only need to store sensitive data temporarily, you should use the cache directory specified by your application in internal storage to store the data. Like files stored in the files directory, files stored in this directory will be deleted when the user uninstalls your application.
Note:
This cache directory is designed to store a small amount of sensitive data for your application.
When the internal storage space of the device is insufficient, Android may delete these cache files to restore the space. Therefore, check if cache files exist before reading them.
// Create a cache file
private void createCache(a) {
try {
/ / method
File timpfile = File.createTempFile("scc2022".".txt".this.getCacheDir());
Log.e("File"."Does it exist?"+timpfile.exists());
Log.e("File"."timpfile:"+timpfile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
// Method 2: Failed to create a file
File file = new File(this.getCacheDir(), "file2022");
Log.e("File"."Does it exist?"+file.exists());
Log.e("File"."file:"+file.getAbsolutePath());
}
Copy the code
Method 1 and method 2 both add files to the application cache directory, but here I used method 2 to create a file and was never successful. Here we focus on method one.
- The first parameter prefix: the prefix of the file name
- The second parameter suffix: filename suffix (if not set, default.tmp)
- The third parameter directory: the directory where the file is stored
As shown above, a random number is added to the end of the file name regardless of whether the suffix is specified to keep the file unique. As the file name above Settings for: scc2022. TXT, but created: scc2022784042118208981946. TXT.
Because adding a random number to the end makes deleting or reading a file difficult, you may need to call file.getName() for file name storage. Otherwise it’s hard to find. I actually prefer the second option, but it’s a little awkward not knowing when it doesn’t work.
3.2 Deleting a File
Although The Android system sometimes deletes cached files itself, you can delete data yourself.
// Delete cached files
private void deleteCache(a) {
/ / scc20221181329566644563700891 scc2022118 and TMP
// The cache directory does not exist
File cacheFile = new File(getCacheDir(), "scc20221181329566644563700891.tmp");
// Check whether the file exists
if(cacheFile.exists())
{
// Use the delete() method on the File object
Log.e("File"."delete17:"+cacheFile.delete());
}
File cacheFile2 = new File(getCacheDir(), "scc2022118");
if(cacheFile2.exists())
{
// Apply the Context deleteFile() method
Log.e("File"."deleteFile19:"+deleteFile("scc2022118")); }}Copy the code
4. External storage
If internal storage is too small to provide more space, external storage can be used
- External Storage
- GetExternalFilesDir ()// Persistent files
- GetExternalCacheDir ()// Cache files
In Android 4.4 (API level >=19), your app can access application-specific directories in external storage without requesting any storage-related permissions. Files stored in these directories will be deleted when your application is uninstalled.
Note:
1. Access to files cannot be guaranteed because the SD card may be removed.
2. On Android 11 (API level >=30), apps cannot create their own app-specific directories on external storage. Feel free to use less external storage.
Verify that the storage is available
// Check whether the external storage is available for reading and writing.
private boolean isExternalStorageWritable(a) {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
// Check that the external storage is at least readable.
private boolean isExternalStorageReadable(a) {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ||
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
}
Copy the code
Share file storage
Store files that your application intends to share with other applications, including media, documents, and other files. Here we save the image to the gallery (shared file).
Requires storage permissions
private void saveBitmap(a) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Check whether the permission has been obtained
int i = ContextCompat.checkSelfPermission(FileStorageActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// Whether the permission has been GRANTED-- authorized DINIED-- refused
if(i ! = PackageManager.PERMISSION_GRANTED) {// If the permission is not granted, prompt the user to request it
startRequestPermission();
} else{ resourceBitmap(); }}else{ resourceBitmap(); }}Copy the code
Save the data
private void resourceBitmap(a) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ceshi);
boolean isSave = PictureStorageUtils.isSaveImage(this, bitmap, "sccgx");
Log.e("File"."isSave:"+isSave);
}
/** * save the image file to local */
public class PictureStorageUtils {
public static boolean isSaveImage(Context context, Bitmap bm, String name) {
boolean isSave;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// The value must be greater than or equal to Android 10
isSave = saveImageQ(context, bm, name);
} else {
isSave = saveImage(context, bm, name);
}
return isSave;
}
private static boolean saveImage(Context context, Bitmap outB, String name) { String imgName = name.isEmpty()? String.valueOf(System.currentTimeMillis()):name;//File. Separator is the File path
String fileName = Environment.getExternalStorageDirectory() + File.separator + "DCIM"
+ File.separator + "demo" + File.separator;
try {
File file = new File(fileName);
if(! file.exists()) { file.mkdirs(); } Log.e("File"."saveAndGetImage:" + file);
File filePath = new File(file + "/" + imgName + ".png");
Log.e("File"."filePath:" + filePath);
FileOutputStream out = new FileOutputStream(filePath); // Save to local JPEG format
if (outB.compress(Bitmap.CompressFormat.PNG, 100, out)) {
out.flush();
out.close();
}
Log.e("File"."saveAndGetImage:END");
// Refresh the gallery
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// A version later than 22 requires manual authorization
// Check whether the permission has been obtained
int i = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// Whether the permission has been GRANTED-- authorized DINIED-- refused
if(i ! = PackageManager.PERMISSION_GRANTED) {// The user should go to the application Settings interface to manually enable permissions
} else {
context.sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(filePath))); }}else {
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(filePath)));
}
return true;
} catch (FileNotFoundException e) {
Log.e("File"."FileNotFoundException e.toString: " + e.toString());
e.printStackTrace();
return false;
} catch (IOException e) {
Log.e("File"."IOException e.toString: " + e.toString());
e.printStackTrace();
return false; }}// Android10 and above save pictures to albums
@RequiresApi(api = Build.VERSION_CODES.Q)
private static boolean saveImageQ(Context context, Bitmap image, String name) {
longmImageTime = System.currentTimeMillis(); String mImageFileName = name.isEmpty()? String.valueOf(mImageTime):name;final ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM
+ File.separator + "demo"); // The folder name shown in the DCIM.
values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
values.put(MediaStore.MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
values.put(MediaStore.MediaColumns.IS_PENDING, 1);
Log.e("File",values.get(MediaStore.MediaColumns.RELATIVE_PATH).toString());
ContentResolver resolver = context.getContentResolver();
final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
try {
// Write down the data for our file
try (OutputStream out = resolver.openOutputStream(uri)) {
if(! image.compress(Bitmap.CompressFormat.PNG,100, out)) {
throw new IOException("Failed to compress"); }}// Everything is going well
values.clear();
values.put(MediaStore.MediaColumns.IS_PENDING, 0);
values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
resolver.update(uri, values, null.null);
return true;
} catch (IOException e) {
Log.e("File",e.getMessage());
return false; }}}Copy the code
Test machine: Galaxy A8s
Image save path: Galaxy A8s Phone DCIM demo
Pixel XL API 31(AS Simulator)
Picture save path: / storage/emulated / 0 / DCIM/demo/SCCGX. PNG
Vi. Project Address
Android data processing scheme