android 中获取目录的API有两种,一种是通过Environment获取,另一种就是通过Context获取。两者获取到的目录区别还是很大的。
通过Environment API获取的目录,不会包含应用的内部目录,也就是带应用包名的目录。
通过Context API获取的目录,绝对路径都会带有改应用的包名,app访问自己包名下的该类文件,不需要额外申请权限
在Android10及以上设备上,即便申请了存储权限,也会报permission Denied . 在manifest文件中,添加: android:requestLegacyExternalStorage= “true”
这里可以将文件归纳为三种:App共享文件、App独立文件、App专属文件
package com.shoneworn.dirmake;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
private TextView tvDir;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvDir = findViewById(R.id.tv_dir);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onResume() {
super.onResume();
// initDir();
if (Utils.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) && Utils.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
initDir();
return;
}
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1000);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults == null || grantResults.length == 0) {
return;
}
if (requestCode != 1000) {
return;
}
if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
initDir();
return;
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initDir() {
StringBuffer sb = new StringBuffer();
File externalStorageDirectory = Environment.getExternalStorageDirectory();
sb.append("Environment externalStorageDirectory>>" + externalStorageDirectory.getAbsolutePath() + "\n");
Log.e("cxx", "Environment externalStorageDirectory>>" + externalStorageDirectory.getAbsolutePath());
makeFile(externalStorageDirectory, "env externalStorageDirectory");
File dataDirectory = Environment.getDataDirectory();
sb.append("Environment dataDirectory>>" + dataDirectory.getAbsolutePath() + "\n");
Log.e("cxx", "Environment dataDirectory>>" + dataDirectory.getAbsolutePath());
makeFile(dataDirectory, "env dataDirectory");
File downloadCacheDirectory = Environment.getDownloadCacheDirectory();
sb.append("Environment downloadCacheDirectory>>" + downloadCacheDirectory.getAbsolutePath() + "\n");
Log.e("cxx", "Environment downloadCacheDirectory>>" + downloadCacheDirectory.getAbsolutePath());
makeFile(downloadCacheDirectory, "env downloadCacheDirectory");
File rootDirectory = Environment.getRootDirectory();
sb.append("Environment rootDirectory>>" + rootDirectory.getAbsolutePath() + "\n");
Log.e("cxx", "Environment rootDirectory>>" + rootDirectory.getAbsolutePath());
makeFile(rootDirectory, "env rootDirectory");
File externalStoragePublicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
sb.append("Environment externalStoragePublicDirectory>>" + externalStoragePublicDirectory.getAbsolutePath() + "\n");
Log.e("cxx", "Environment externalStoragePublicDirectory>>" + externalStoragePublicDirectory.getAbsolutePath());
makeFile(externalStoragePublicDirectory, "env externalStoragePublicDirectory");
Context context = this;
File externalFilesDir = context.getExternalFilesDir(null);
sb.append("Context externalFilesDir>>" + externalFilesDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context externalFilesDir>>" + externalFilesDir.getAbsolutePath());
makeFile(externalFilesDir, "externalFilesDir");
File externalCacheDir = context.getExternalCacheDir();
sb.append("Context externalCacheDir>>" + externalCacheDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context externalCacheDir>>" + externalCacheDir.getAbsolutePath());
makeFile(externalCacheDir, "externalCacheDir");
File[] externalCacheDirs = context.getExternalCacheDirs();
sb.append("Context externalCacheDirs>>");
for (File file : externalCacheDirs) {
sb.append(file.getAbsolutePath() + " ");
Log.e("cxx", "Context externalCacheDirs>>" + file.getAbsolutePath());
}
sb.append("\n");
File filesDir = context.getFilesDir();
sb.append("Context filesDir>>" + filesDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context filesDir>>" + filesDir.getAbsolutePath());
makeFile(filesDir, "filesDir");
File cacheDir = context.getCacheDir();
sb.append("Context cacheDir>>" + cacheDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context cacheDir>>" + cacheDir.getAbsolutePath());
makeFile(cacheDir, "cacheDir");
File codeCacheDir = context.getCodeCacheDir();
sb.append("Context codeCacheDir>>" + codeCacheDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context codeCacheDir>>" + codeCacheDir.getAbsolutePath());
makeFile(codeCacheDir, "codeCacheDir");
File noBackupFilesDir = context.getNoBackupFilesDir();
sb.append("Context noBackupFilesDir>>" + noBackupFilesDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context noBackupFilesDir>>" + noBackupFilesDir.getAbsolutePath());
makeFile(noBackupFilesDir, "noBackupFilesDir");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
File dataDir = context.getDataDir();
sb.append("Context dataDir>>" + dataDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context dataDir>>" + dataDir.getAbsolutePath());
makeFile(dataDir, "dataDir");
}
File[] externalMediaDirs = context.getExternalMediaDirs();
sb.append("Context externalMediaDirs>>");
for (File file : externalMediaDirs) {
sb.append(file.getAbsolutePath() + " ");
Log.e("cxx", "Context externalMediaDirs>>" + file.getAbsolutePath());
}
sb.append("\n");
File obbDir = context.getObbDir();
sb.append("Context obbDir>>" + obbDir.getAbsolutePath() + "\n");
Log.e("cxx", "Context obbDir>>" + obbDir.getAbsolutePath());
makeFile(obbDir, "obbDir");
String s = sb.toString();
tvDir.setText(s);
}
//向各个目录下写入文件
private void makeFile(File dir, String name) {
if (dir == null || !dir.exists()) {
return;
}
try {
File file = new File(dir, "cxx.txt");
if (!file.exists()) {
file.createNewFile();
}
OutputStreamWriter out = new OutputStreamWriter(
new FileOutputStream(file, false), // true to append
"UTF-8"
);
out.write(getPackageName() + " name:" + name + " dir>>" + dir.getAbsolutePath());
out.close();
} catch (Exception e) {
Log.e("cxx", e.getMessage());
}
}
}
看下输出:
E/cxx: Environment externalStorageDirectory>>/storage/emulated/0
E/cxx: Environment dataDirectory>>/data
E/cxx: Permission denied
E/cxx: Environment downloadCacheDirectory>>/data/cache
E/cxx: Permission denied
E/cxx: Environment rootDirectory>>/system
E/cxx: Read-only file system
E/cxx: Environment externalStoragePublicDirectory>>/storage/emulated/0/DCIM
//从这里开始,均由context获取的目录,访问不需要申请应用权限,随app卸载而删除
//系统分区下的app私有目录
E/cxx: Context externalFilesDir>>/storage/emulated/0/Android/data/com.shoneworn.dirmake/files
E/cxx: Context externalCacheDir>>/storage/emulated/0/Android/data/com.shoneworn.dirmake/cache
E/cxx: Context externalCacheDirs>>/storage/emulated/0/Android/data/com.shoneworn.dirmake/cache
E/cxx: Context externalMediaDirs>>/storage/emulated/0/Android/media/com.shoneworn.dirmake
E/cxx: Context obbDir>>/storage/emulated/0/Android/obb/com.shoneworn.dirmake
//sdcard下应用独有目录
E/cxx: Context filesDir>>/data/user/0/com.shoneworn.dirmake/files
E/cxx: Context cacheDir>>/data/user/0/com.shoneworn.dirmake/cache
E/cxx: Context codeCacheDir>>/data/user/0/com.shoneworn.dirmake/code_cache
E/cxx: Context noBackupFilesDir>>/data/user/0/com.shoneworn.dirmake/no_backup
E/cxx: Context dataDir>>/data/user/0/com.shoneworn.dirmake
可以看到有两个目录下创建文件被拒了。应用想要向这两个目录下创建文件,需要root权限。
package com.shoneworn.readfile;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.Buffer;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_ext_cache).setOnClickListener(this);
findViewById(R.id.btn_ext_file).setOnClickListener(this);
findViewById(R.id.btn_file_dir).setOnClickListener(this);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onResume() {
super.onResume();
if (Utils.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) && Utils.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
return;
}
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1000);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults == null || grantResults.length == 0) {
return;
}
if (requestCode != 1000) {
return;
}
if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
return;
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_ext_file:
readFile("/storage/emulated/0/Android/data/com.shoneworn.dirmake/files");
break;
case R.id.btn_file_dir:
readFile("/data/user/0/com.shoneworn.dirmake/files");
break;
case R.id.btn_ext_cache:
readFile("/storage/emulated/0/Android/data/com.shoneworn.dirmake/cache");
break;
}
}
private void readFile(String path) {
File file = new File(path + File.separator + "cxx.txt");
if (!file.exists()) {
Log.e("cxx", "read " + file.getAbsolutePath() + " not exists");
return;
}
try {
StringBuilder sb = new StringBuilder();
FileInputStream fileInputStream = new FileInputStream(file);
byte[] buffer = new byte[1024];
int len = fileInputStream.read(buffer);
while (len > 0) {
sb.append(new String(buffer, 0, len));
len = fileInputStream.read(buffer);
}
fileInputStream.close();
String s = sb.toString();
Log.e("cxx", path + " content:" + s);
} catch (Exception e) {
Log.e("cxx", e.getMessage());
}
}
}
看看日志:
E/cxx: /storage/emulated/0/Android/data/com.shoneworn.dirmake/files content:com.shoneworn.dirmake name:externalFilesDir dir>>/storage/emulated/0/Android/data/com.shoneworn.dirmake/files
E/cxx: read /data/user/0/com.shoneworn.dirmake/files/cxx.txt not exists
E/cxx: /storage/emulated/0/Android/data/com.shoneworn.dirmake/cache content:com.shoneworn.dirmake name:externalCacheDir dir>>/storage/emulated/0/Android/data/com.shoneworn.dirmake/cache
这里只演示了访问其他应用app独立文件和其他应用app专属文件的情况。
访问其他应用app专属文件时直接文件不存在。
Demo下载地址
https://download.csdn.net/download/shoneworn/14046663