
本文共 11964 字,大约阅读时间需要 39 分钟。
文章目录
Access app-specific files
In many cases, your app creates files that other apps don’t need to access, or shouldn’t access. The system provides the following locations for storing such app-specific files:
- Internal storage directories: These directories include both a dedicated location for storing persistent files, and another location for storing cache data. The system prevents other apps from accessing these locations, and on Android 10 (API level 29) and higher, these locations are encrypted. These characteristics make these locations a good place to store sensitive data that only your app itself can access.
- External storage directories: These directories include both a dedicated location for storing persistent files, and another location for storing cache data. Although it’s possible for another app to access these directories if that app has the proper permissions, the files stored in these directories are meant for use only by your app. If you specifically intend to create files that other apps should be able to access, your app should store these files in the part of external storage instead.
When the user uninstalls your app, the files saved in app-specific storage are removed. Because of this behavior, you shouldn’t use this storage to save anything that the user expects to persist independently of your app. For example, if your app allows users to capture photos, the user would expect that they can access those photos even after they uninstall your app. So you should instead use shared storage to save those types of files to the appropriate .
Note: To further protect app-specific files, use the that’s part of to encrypt these files at rest. The encryption key is specific to your app.
The following sections describe how to store and access files within app-specific directories.
Access from internal storage
For each app, the system provides directories within internal storage where an app can organize its files. One directory is designed for , and another contains . Your app doesn’t require any system permissions to read and write to files in these directories.
Other apps cannot access files stored within internal storage. This makes internal storage a good place for app data that other apps shouldn’t access.
Keep in mind, however, that these directories tend to be small. Before writing app-specific files to internal storage, your app should on the device.
Access persistent files
Your app’s ordinary, persistent files reside in a directory that you can access using the property of a context object. The framework provides several methods to help you access and store files in this directory.
Access and store files
You can use the API to access and store files.
To help maintain your app’s performance, don’t open and close the same file multiple times.
The following code snippet demonstrates how to use the File
API:
File file = new File(context.getFilesDir(), filename);
Store a file using a stream
As an alternative to using the File
API, you can call [openFileOutput()
](https://developer.android.google.cn/reference/android/content/Context#openFileOutput(java.lang.String, int)) to get a that writes to a file within the filesDir
directory.
The following code snippet shows how to write some text to a file:
String filename = "myfile";String fileContents = "Hello world!";try (FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE)) { fos.write(fileContents.toByteArray());}
Caution: On devices that run Android 7.0 (API level 24) or higher, unless you pass the
Context.MODE_PRIVATE
file mode intoopenFileOutput()
, a occurs.
To stored in this directory within internal storage, use a with the attribute.
Access a file using a stream
To read a file as a stream, use :
FileInputStream fis = context.openFileInput(filename);InputStreamReader inputStreamReader = new InputStreamReader(fis, StandardCharsets.UTF_8);StringBuilder stringBuilder = new StringBuilder();try (BufferedReader reader = new BufferedReader(inputStreamReader)) { String line = reader.readLine(); while (line != null) { stringBuilder.append(line).append('\n'); line = reader.readLine(); }} catch (IOException e) { // Error occurred when opening raw file for reading.} finally { String contents = stringBuilder.toString();}
Note: If you need to access a file as a stream at install time, save the file in your project’s
/res/raw
directory. You can open these files with , passing in the filename prefixed withR.raw
as the resource ID. This method returns an that you can use to read the file. You cannot write to the original file.
View list of files
You can get an array containing the names of all files within the filesDir
directory by calling , as shown in the following code snippet:
Arrayfiles = context.fileList();
Create nested directories
You can also create nested directories, or open an inner directory, by calling in Kotlin-based code or by passing the root directory and a new directory name into a File
constructor in Java-based code:
File directory = context.getFilesDir();File file = new File(directory, filename);
Note:
filesDir
is always an ancestor directory of this new directory.
Create cache files
If you need to store sensitive data only temporarily, you should use the app’s designated cache directory within internal storage to save the data. As is the case for all app-specific storage, the files stored in this directory are removed when the user uninstalls your app, although the files in this directory might be .
Note: This cache directory is designed to store a small amount of your app’s sensitive data. To determine how much cache space is currently available for your app, call .
To create a cached file, call [File.createTempFile()
](https://developer.android.google.cn/reference/java/io/File#createTempFile(java.lang.String, java.lang.String)):
File.createTempFile(filename, null, context.getCacheDir());
Your app accesses a file in this directory using the property of a context object and the API:
File cacheFile = new File(context.getCacheDir(), filename);
Caution: When the device is low on internal storage space, Android may delete these cache files to recover space. So check for the existence of your cache files before reading them.
Remove cache files
Even though Android sometimes deletes cache files on its own, you shouldn’t rely on the system to clean up these files for you. You should always maintain your app’s cache files within internal storage.
To remove a file from the cache directory within internal storage, use one of the following methods:
-
The method on a
File
object that represents the file:cacheFile.delete();
-
The method of the app’s context, passing in the name of the file:
context.deleteFile(cacheFileName);
准备
IDE:
Android Studio 4.1.1Build #AI-201.8743.12.41.6953283, built on November 5, 2020Runtime version: 1.8.0_242-release-1644-b01 amd64VM: OpenJDK 64-Bit Server VM by JetBrains s.r.oWindows 10 10.0
Android Virtual Devices:
Name: Pixel_2_API_28CPU/ABI: Google Play Intel Atom (x86)Path: C:\Users\86188\.android\avd\Pixel_2_API_28.avdTarget: google_apis_playstore [Google Play] (API level 28)Skin: pixel_2SD Card: 512Mfastboot.chosenSnapshotFile: runtime.network.speed: fullhw.accelerometer: yeshw.device.name: pixel_2hw.lcd.width: 1080hw.initialOrientation: Portraitimage.androidVersion.api: 28tag.id: google_apis_playstorehw.mainKeys: nohw.camera.front: emulatedavd.ini.displayname: Pixel 2 API 28hw.gpu.mode: autohw.ramSize: 1536PlayStore.enabled: truefastboot.forceColdBoot: nohw.cpu.ncore: 4hw.keyboard: yeshw.sensors.proximity: yeshw.dPad: nohw.lcd.height: 1920vm.heapSize: 256skin.dynamic: yeshw.device.manufacturer: Googlehw.gps: yeshw.audioInput: yesimage.sysdir.1: system-images\android-28\google_apis_playstore\x86\showDeviceFrame: yeshw.camera.back: virtualsceneAvdId: Pixel_2_API_28hw.lcd.density: 420hw.arc: falsehw.device.hash2: MD5:55acbc835978f326788ed66a5cd4c9a7fastboot.forceChosenSnapshotBoot: nofastboot.forceFastBoot: yeshw.trackBall: nohw.battery: yeshw.sdCard: yestag.display: Google Playruntime.network.latency: nonedisk.dataPartition.size: 6442450944hw.sensors.orientation: yesavd.ini.encoding: UTF-8hw.gpu.enabled: yes
注意:以下示例仅在安卓虚拟设备上运行测试,并没有在真实的设备上运行测试。
访问内部存储
应用特定的文件存储在 data/data/app_name/ 目录中,可以使用 Device File Explorer 查看。
菜单:View > Tool Windows > Device File Explorer
效果:
编辑 src\main\res\layout\activity_main.xml
布局文件:
编辑 MainActivity
:
package com.mk;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private static final String FILE_NAME = "app-specific.txt"; private File file; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); file = new File(getFilesDir(), FILE_NAME); ((Button) findViewById(R.id.buttonStoreToFile)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String content = ((EditText) findViewById(R.id.editText)).getText().toString(); // 写字符串到文件 try { writeStringToFile(file, content); } catch (IOException e) { e.printStackTrace(); } // 列出所有文件(方式一) for (File file : getFilesDir().listFiles()) { Log.d(TAG, "onCreate: " + file.getAbsolutePath()); } } }); ((Button) findViewById(R.id.buttonRetrieveFromFile)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 读取文件的内容 try { String content = readStringFromFile(file); Toast.makeText(MainActivity.this, content, Toast.LENGTH_LONG).show(); } catch (IOException e) { e.printStackTrace(); } } }); ((Button) findViewById(R.id.buttonDeleteFile)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (file.delete()) Toast.makeText(MainActivity.this, "删除成功", Toast.LENGTH_LONG).show(); else Toast.makeText(MainActivity.this, "删除失败,文件可能不存在!", Toast.LENGTH_LONG).show(); // 列出所有文件(方式二) for (String file : fileList()) { Log.d(TAG, "onCreate: " + file); } } }); } private void writeStringToFile(File file, String content) throws IOException { FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(content.getBytes()); fileOutputStream.flush(); fileOutputStream.close(); } private String readStringFromFile(File file) throws IOException { FileInputStream fileInputStream = new FileInputStream(file); final InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); final BufferedReader bufferedReader = new BufferedReader(inputStreamReader); StringBuilder content = new StringBuilder(); char[] buffer = new char[1024]; for (int length = bufferedReader.read(buffer); length != -1; length = bufferedReader.read(buffer)) { content.append(buffer, 0, length); } return content.toString(); }}
参考
发表评论
最新留言
关于作者
