IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 文件存储 -> 正文阅读

[移动开发]Android 文件存储

Android 存储空间操作

一、专属存储空间

1.1.内部存储空间

1.1.1 在专属存储空间写入一个文件:

String filename = "myfile";
String fileContents = "Hello world!";
try (FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE)) {
    fos.write(fileContents.toByteArray());
}

1.1.2 读取在存储存储空间的文件:

        FileInputStream fis = null;
        try {
            fis = this.openFileInput("demoFile");
            InputStreamReader inputStreamReader = new InputStreamReader(fis, StandardCharsets.UTF_8);
            String fileContents = null;
            BufferedReader reader = new BufferedReader(inputStreamReader)
                fileContents = reader.readLine();
            Log.d("FileContents: ", fileContents);
        } catch (IOException e) {
            e.printStackTrace();
        }

1.1.3 获取存储空间内的文件列表:

        String[] fileList = this.fileList();

1.1.4 创建嵌套目录

        File directory = this.getFilesDir();
        File file = new File(directory, filename);

1.1.5 创建缓存文件

        try {
            File.createTempFile(filename, null, this.getCacheDir());
        } catch (IOException e) {
            e.printStackTrace();
        }

1.1.6 访问缓存文件

File file = new File(this.getCacheDir(), filename);

1.1.7 移除缓存文件

File file = new File(this.getCacheDir(), filename);
file.delete();

//或者使用上下文的deleteFile()方法
this.deleteFile(cacheFileName);

1.2 外部存储空间

在 Android 4.4(API 级别 19)或更高版本中,应用无需请求任何与存储空间相关的权限即可访问外部存储空间中的应用专属目录。卸载应用后,系统会移除这些目录中存储的文件。

在搭载 Android 9(API 级别 28)或更低版本的设备上,只要您的应用具有适当的存储权限,就可以访问属于其他应用的应用专用文件。为了让用户更好地管理自己的文件并减少混乱,以 Android 10(API 级别 29)及更高版本为目标平台的应用在默认情况下被授予了对外部存储空间的分区访问权限(即分区存储)。启用分区存储后,应用将无法访问属于其他应用的应用专属目录。

1.2.1 验证存储空间的可用性

// Checks if a volume containing external storage is available
// 可读可写
private boolean isExternalStorageWritable() {
    return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}

// 至少是可读的
private boolean isExternalStorageReadable() {
     return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ||
            Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
}

1.2.2 选择物理存储位置

除非该卷已满或者不可用,否则使用该卷;

File[] externalStorageVolumes =
        ContextCompat.getExternalFilesDirs(getApplicationContext(), null);
//[/storage/emulated/0/Android/data/zjut.edu.musicplayer/files, /storage/1514-0610/Android/data/zjut.edu.musicplayer/files]
File primaryExternalStorage = externalStorageVolumes[0];

1.2.3 访问持久性文件

File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);

1.2.4 创建缓存文件

File externalCacheFile = new File(context.getExternalCacheDir(), filename);

1.2.5 移除缓存文件

externalCacheFile.delete();

1.2.6 媒体内容

如果应用支持使用仅在您的应用内对用户有价值的媒体文件,最好将这些文件存储在外部存储空间的应用专属目录中:

@Nullable
File getAppSpecificAlbumStorageDir(Context context, String albumName) {
    // Get the pictures directory that's inside the app-specific directory on
    // external storage.
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (file == null || !file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

1.3 查询可用空间

getAllocatableByte()方法可以查出设备可以为应用提供多少空间,getAllocatableBytes() 的返回值可能大于设备上的当前可用空间量。这是因为系统已识别出可以从其他应用的缓存目录中移除的文件。

如果有足够的空间保存您的应用数据,请调用 [allocateBytes()](https://developer.android.google.cn/reference/android/os/storage/StorageManager?hl=zh-cn#allocateBytes(java.io.FileDescriptor, long))。否则,您的应用可以请求用户从设备移除一些文件或从设备移除所有缓存文件

// app需要10MB内部空间
private static final long NUM_BYTES_NEEDED_FOR_MY_APP = 1024 * 1024 * 10L;
//获取存储管理器
StorageManager storageManager =
        getApplicationContext().getSystemService(StorageManager.class);
UUID appSpecificInternalDirUuid = storageManager.getUuidForPath(getFilesDir());
long availableBytes =
        storageManager.getAllocatableBytes(appSpecificInternalDirUuid);
if (availableBytes >= NUM_BYTES_NEEDED_FOR_MY_APP) {
    storageManager.allocateBytes(
            appSpecificInternalDirUuid, NUM_BYTES_NEEDED_FOR_MY_APP);
} else {
    // 请求从设备移除所有缓存文件
    Intent storageIntent = new Intent();
    storageIntent.setAction(ACTION_MANAGE_STORAGE);
}

二、共享存储空间

Android 提供用于存储和访问以下类型的可共享数据的 API:

  • 媒体内容:系统提供标准的公共目录来存储这些类型的文件,这样用户就可以将所有照片保存在一个公共位置,将所有音乐和音频文件保存在另一个公共位置,依此类推。您的应用可以使用此平台的 MediaStore API 访问此内容。
  • 文档和其他文件:系统有一个特殊目录,用于包含其他文件类型,例如 PDF 文档和采用 EPUB 格式的图书。您的应用可以使用此平台的存储访问框架访问这些文件。
  • 数据集:在 Android 11(API 级别 30)及更高版本中,系统会缓存多个应用可能使用的大型数据集。这些数据集可为机器学习和媒体播放等用例提供支持。应用可以使用 BlobStoreManager API 访问这些共享数据集。

系统会自动扫描外部存储卷,并将媒体文件添加到以下明确定义的集合中:

  • 图片(包括照片和屏幕截图),存储在 DCIM/Pictures/ 目录中。系统将这些文件添加到 MediaStore.Images 表格中。
  • 视频,存储在 DCIM/Movies/Pictures/ 目录中。系统将这些文件添加到 MediaStore.Video 表格中。
  • 音频文件,存储在 Alarms/Audiobooks/Music/Notifications/Podcasts/Ringtones/ 目录中。此外,系统还可以识别 Music/Movies/ 目录中的音频播放列表,以及 Recordings/ 目录中的录音。系统将这些文件添加到 MediaStore.Audio 表格中。录音目录在 Android 11(API 级别 30)及更低版本中不可用。
  • 下载的文件,存储在 Download/ 目录中。在搭载 Android 10(API 级别 29)及更高版本的设备上,这些文件存储在 MediaStore.Downloads 表格中。此表格在 Android 9(API 级别 28)及更低版本中不可用。

媒体库还包含一个名为 MediaStore.Files 的集合。其内容取决于您的应用是否使用分区存储(适用于以 Android 10 或更高版本为目标平台的应用):

  • 如果启用了分区存储,集合只会显示您的应用创建的照片、视频和音频文件。大多数开发者无需使用 MediaStore.Files 即可查看其他应用的媒体文件,但如果您有特定要求,则可以声明 READ_EXTERNAL_STORAGE 权限。不过,建议您使用 MediaStore API 打开您的应用尚未创建的文件
  • 如果分区存储不可用或未使用,集合将显示所有类型的媒体文件。

2.1 请求权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="28" />

请勿多此一举为搭载 Android 10 或更高版本的设备请求存储相关权限。您的应用可以提供明确定义的媒体集合,包括 MediaStore.Downloads 集合,而无需请求任何存储相关权限。例如,如果您正在开发一款相机应用,您无需请求存储相关权限,因为您的应用拥有您将写入媒体库的图片

如需访问由其他应用创建的文件,必须满足以下所有条件:

如果您的应用在搭载 Android 9 或更低版本的设备上使用,或者您的应用暂时停用分区存储,您必须请求 READ_EXTERNAL_STORAGE 权限才能访问媒体文件。如果要修改媒体文件,您还必须请求 WRITE_EXTERNAL_STORAGE 权限。

如果您的应用以 Android 10(API 级别 29)或更高版本为目标平台,为了使您的应用从照片中检索未编辑的 Exif 元数据,您需要在应用的清单中声明 ACCESS_MEDIA_LOCATION 权限,然后在运行时请求此权限。

<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>

2.2 检查媒体库更新

如需更可靠地访问媒体文件,尤其是在应用缓存来自媒体库的 URI 或数据时,请检查媒体库版本与上次同步媒体数据时相比是否发生了变化。如需执行此更新检查,请调用 [getVersion()](https://developer.android.google.cn/reference/android/provider/MediaStore?hl=zh-cn#getVersion(android.content.Context, java.lang.String))。返回的版本是一个唯一字符串,该字符串会在媒体库发生重大变化时随之变化。如果返回的版本与上次同步的版本不同,请重新扫描并重新同步应用的媒体缓存。

2.3 查询媒体集合

例子:查询时长超过5分钟的媒体,使用如下类似SQL的选择语句:

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your
// app didn't create.

// 媒体信息容器类
class Video {
    private final Uri uri;
    private final String name;
    private final int duration;
    private final int size;

    public Video(Uri uri, String name, int duration, int size) {
        this.uri = uri;
        this.name = name;
        this.duration = duration;
        this.size = size;
    }
}
//媒体列表
List<Video> videoList = new ArrayList<Video>();
//判断版本
Uri collection;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
} else {
    //老版本方法
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}

String[] projection = new String[] {
    MediaStore.Video.Media._ID,
    MediaStore.Video.Media.DISPLAY_NAME,
    MediaStore.Video.Media.DURATION,
    MediaStore.Video.Media.SIZE
};
//媒体时长超过
String selection = MediaStore.Video.Media.DURATION +
        " >= ?";
//选择参数 5分钟:300s
String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));
};
//根据文件名升序排列
String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC";

try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,
    projection,
    selection,
    selectionArgs,
    sortOrder
)) {
    
    //获取列号
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);
    int nameColumn =
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
    int durationColumn =
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);

    while (cursor.moveToNext()) {
        //读取各行信息
        long id = cursor.getLong(idColumn);
        String name = cursor.getString(nameColumn);
        int duration = cursor.getInt(durationColumn);
        int size = cursor.getInt(sizeColumn);

        Uri contentUri = ContentUris.withAppendedId(
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);

        // Stores column values and the contentUri in a local object
        // that represents the media file.
        videoList.add(new Video(contentUri, name, duration, size));
    }
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-27 17:21:58  更:2022-05-27 17:23:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 0:43:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码