Android文件存储路径分析

本文详细分析了Android设备中内部存储和外部存储的区别,包括访问权限、文件共享、卸载APP后的处理以及不同Android版本下的路径变化。在内部存储中,文件仅限本App访问,而外部存储允许与其他APP共享,但需关注权限管理和外部存储的可用性。文章提供了存储文件到内外部存储的代码示例,并总结了不同Android版本下的文件存储路径规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.internal or external storage

image
image
内部存储和外部存储的对比:
1.内部存储永远可以访问,由于外部存储可能是SD卡,可能无法访问;
2.内部存储文件只有本App才能访问,外部存储文件可以共享给其他APP;
3.卸载APP,相应的内部存储文件被系统删除;对于外部存储,除非使用getExternalFilesDir()方法,APP删除,相应的文件不被删除;
4.访问内部存储文件,不需要申请权限;

2.存储文件到内部存储

  在没有root的前提下,内部存储目录是隐藏不可见的;访问内部存储目录时,不需要申请系统权限;由于从Android6.0开始支持多用户,内部存储目录路径从之前的/data/data变成了/data/user/0 。
1.getFilesDir();
/data/user/0/packname/files
2.getCacheDir();
/data/user/0/packname/cache

3.存储文件到外部存储

3.1 申请权限

  同时申请读写外部存储权限:

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

  从Android4.4开始,getExternalFilesDir()和getExternalCacheDir()方法不需要申请权限;所以如果你的App支持4.3或者更低版本,并且你要访问私有文件,你需要这么申请权限:

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

3.2 判断外部存储是否可用

  因为外部存储可能不可用——例如当用户将存储挂载到PC上或删除SD卡时——在访问卷之前,您必须验证外部存储是否可用。您可以通过调用getExternalStorageState()方法来查询外部存储状态。

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

3.3 Public files

  在申请权限并且确定外部存储可用后,外部存储文件有两种类型:
  Public files:公共文件其他App可以访问,路径例如/storage/emulated/0/Documents;卸载当前App后,这些文件仍然保留。例如:DCIM,MUSIC等。

3.4 Private files

  Private files:因为这些文件本身属于外部存储文件,所以通过一些方法能被其他App访问;但是这些文件属于对应的APP,路径例如/storage/emulated/0/Android/data/packagename/cache当App删除后,这些文件也被删除。

4.测试Demo

package com.example.davidhuang.storagepath;

import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.support.annotation.RequiresApi;
import android.support.v4.os.EnvironmentCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "Storage Path";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //内部存储
        Log.i(TAG ,"getCacheDir()---->" + getCacheDir().getAbsolutePath());
        Log.i(TAG ,"getFilesDir()---->" + getFilesDir().getAbsolutePath());
        Log.i(TAG, "getDir()---->" + getDir("myfile", Context.MODE_PRIVATE));

        Log.i(TAG, "Environment.getDataDirectory()---->" + Environment.getDataDirectory().getAbsolutePath());
        Log.i(TAG, "Environment.getRootDirectory()---->" + Environment.getRootDirectory().getAbsolutePath());
        Log.i(TAG, "Environment.getDownloadCacheDirectory()---->" + Environment.getDownloadCacheDirectory().getAbsolutePath());
        Log.i(TAG, "getPackageResourcePath()---->" + getPackageResourcePath());
        //外部存储
        if(!isExternalStorageWritable()){
            Log.w(TAG, "External Storage is not Writable!");
            return;
        }
        /**
         * 外部存储公共文件目录,手动创建
         * 一个参数,表明目录所放的文件类型,传入的参数是Environment类中的DIRECTORY_XXX静态变量,比如DIRECTORY_DCIM,DIRECTORY_MUSIC等.
         * 注意:传入的类型参数不能是null,返回的目录路径有可能不存在,所以必须在使用之前确认一下。
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4以前不支持下列获取路径的方法
            File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
            if( !path.exists() ){
                path.mkdirs();
            }
            Log.i(TAG, "Environment.getExternalStoragePublicDirectory()---->" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS));
            //外部存储私有文件目录
            Log.i(TAG, "getExternalCacheDir()---->" + getExternalCacheDir().getAbsolutePath());
            Log.i(TAG, "getExternalFilesDir()---->" + getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath());
        }
        Log.i(TAG, "Environment.getExternalStorageDirectory()---->" + Environment.getExternalStorageDirectory().getAbsolutePath());
    }
    
    /* Checks if external storage is available for read and write */
    public boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            return true;
        }
        return false;
    }

    /* Checks if external storage is available to at least read */
    public boolean isExternalStorageReadable() {
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state) ||
                Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            return true;
        }
        return false;
    }
}

输出:
Android 4.3 模拟器

getCacheDir()---->/data/data/com.example.davidhuang.storagepath/cache
getFilesDir()---->/data/data/com.example.davidhuang.storagepath/files
getDir()---->/data/data/com.example.davidhuang.storagepath/app_myfile
Environment.getDataDirectory()---->/data
Environment.getRootDirectory()---->/system
Environment.getDownloadCacheDirectory()---->/cache
getPackageResourcePath()---->/data/app/com.example.davidhuang.storagepath-2.apk

Environment.getExternalStorageDirectory()---->/storage/sdcard

Android 4.4 ,5.0模拟器

getCacheDir()---->/data/data/com.example.davidhuang.storagepath/cache
getFilesDir()---->/data/data/com.example.davidhuang.storagepath/files
getDir()---->/data/data/com.example.davidhuang.storagepath/app_myfile
Environment.getDataDirectory()---->/data
Environment.getRootDirectory()---->/system
Environment.getDownloadCacheDirectory()---->/cache
getPackageResourcePath()--->/data/app/com.example.davidhuang.storagepath-1.apk
    
Environment.getExternalStoragePublicDirectory()---->
/storage/sdcard/Documents
getExternalCacheDir()---->
/storage/sdcard/Android/data/com.example.davidhuang.storagepath/cache
getExternalFilesDir()---->
/storage/sdcard/Android/data/com.example.davidhuang.storagepath/files/DCIM
Environment.getExternalStorageDirectory()---->/storage/sdcard

Android 6.0,7.0,8.0,9.0模拟器
Android 8.0 魅族16X真机

getCacheDir()---->/data/user/0/com.example.davidhuang.storagepath/cache
getFilesDir()---->/data/user/0/com.example.davidhuang.storagepath/files
getDir()---->/data/user/0/com.example.davidhuang.storagepath/app_myfile
Environment.getDataDirectory()---->/data
Environment.getRootDirectory()---->/system
Environment.getDownloadCacheDirectory()---->/data/cache
getPackageResourcePath()---->/data/app/com.example.davidhuang.storagepath-i1NCmia3ALItNcV3Rkyk8A==/base.apk

Environment.getExternalStoragePublicDirectory()---->/storage/emulated/0/Documents
Environment.getExternalStorageDirectory()---->/storage/emulated/0
getExternalCacheDir()---->
/storage/emulated/0/Android/data/com.example.davidhuang.storagepath/cache
getExternalFilesDir()---->
/storage/emulated/0/Android/data/com.example.davidhuang.storagepath/files/DCIM

4.文件存储路径总结

(1)Android4.4以前

getCacheDir()---->/data/data/packagename/cache
getFilesDir()---->/data/data/packagename/files
getDir()---->/data/data/packagename/app_myfile
Environment.getDataDirectory()---->/data
Environment.getRootDirectory()---->/system
Environment.getDownloadCacheDirectory()---->/cache
getPackageResourcePath()---->/data/app/packagename-2.apk

Environment.getExternalStorageDirectory()---->/storage/sdcard

(2)Android4.4级以后,Android6.0以前

getCacheDir()---->/data/data/packagename/cache
getFilesDir()---->/data/data/packagename/files
getDir()---->/data/data/packagename/app_myfile
Environment.getDataDirectory()---->/data
Environment.getRootDirectory()---->/system
Environment.getDownloadCacheDirectory()---->/cache
getPackageResourcePath()--->/data/app/packagename-1.apk

Environment.getExternalStoragePublicDirectory()---->/storage/sdcard/Documents
getExternalCacheDir()---->/storage/sdcard/Android/data/packagename/cache
getExternalFilesDir()---->/storage/sdcard/Android/data/packagename/files/DCIM
Environment.getExternalStorageDirectory()---->/storage/sdcard

(3)Android6.0以后

getCacheDir()---->/data/user/0/packagename/cache
getFilesDir()---->/data/user/0/packagename/files
getDir()---->/data/user/0/packagename/app_myfile
Environment.getDataDirectory()---->/data
Environment.getRootDirectory()---->/system
Environment.getDownloadCacheDirectory()---->/data/cache
getPackageResourcePath()---->/data/app/packagename-num.apk(8.0以前)
getPackageResourcePath()---->/data/app/packagename-i1NCmia3ALItNcV3Rkyk8A==/base.apk(8.0及以后)

Environment.getExternalStoragePublicDirectory()---->/storage/emulated/0/Documents
Environment.getExternalStorageDirectory()---->/storage/emulated/0
getExternalCacheDir()---->/storage/emulated/0/Android/data/packagename/cache
getExternalFilesDir()---->/storage/emulated/0/Android/data/packagename/files/DCIM
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值