Android开发-存储卡的文件操作

在Android应用开发中,文件操作是常见的需求之一。除了内部存储外,外部存储(如SD卡)也经常用于保存用户数据、图片、日志文件等较大体积的内容。本文将详细介绍如何在Android中进行外部存储(即存储卡)的文件读写操作,包括权限申请、路径获取、文件创建与读写等内容,并提供示例代码帮助你快速上手。

一、Android中的存储类型简介

(一)内部存储(Internal Storage)

  • 应用私有目录,卸载后自动删除。
  • 不需要额外权限即可访问。
  • 路径:/data/data/<package-name>/

(二)外部存储(External Storage)

  • 包括设备自带的“扩展存储”和插入的SD卡。
  • 可被其他应用或用户访问。
  • 需要申请权限才能进行读写操作。
  • 路径:/storage/emulated/0/ 或 /storage/sdcard1/ 等。

二、权限声明与适配

从Android 6.0(API 23)开始,系统引入了运行时权限机制;从Android 10(API 29)起,Google进一步限制了对公共目录的直接访问,推荐使用Scoped Storage(作用域存储)方式。

(一)在AndroidManifest.xml中添加权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"/> <!-- 仅适用于Android 9及以下 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"/>

⚠️ 注意:从Android 10开始,官方建议使用MediaStore API或Storage Access Framework来访问共享目录,避免使用直接路径访问。

三、获取外部存储路径

(一)获取外部存储根目录

File externalStorageDir = Environment.getExternalStorageDirectory();
Log.d("Path", "External Storage Dir: " + externalStorageDir.getAbsolutePath());

(二)获取特定类型的公共目录(如Download、Pictures等)

File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
Log.d("Path", "Download Dir: " + downloadDir.getAbsolutePath());

(三)获取应用专属的外部缓存目录(无需权限)

File cacheDir = getExternalCacheDir();
Log.d("Path", "App External Cache Dir: " + cacheDir.getAbsolutePath());

四、文件操作示例

(一)创建文件并写入内容

try {
    File file = new File(downloadDir, "test.txt");
    if (!file.exists()) {
        file.createNewFile(); // 创建文件
    }

    FileOutputStream fos = new FileOutputStream(file);
    String content = "Hello, this is a test file.";
    fos.write(content.getBytes());
    fos.close();

    Log.d("File", "文件写入成功!");
} catch (IOException e) {
    e.printStackTrace();
}

(二)读取文件内容

try {
    File file = new File(downloadDir, "test.txt");
    FileInputStream fis = new FileInputStream(file);
    byte[] data = new byte[(int) file.length()];
    fis.read(data);
    fis.close();

    String text = new String(data, StandardCharsets.UTF_8);
    Log.d("File", "读取内容:" + text);
} catch (IOException e) {
    e.printStackTrace();
}

五、运行时权限请求(针对Android 6.0及以上)

如果你的应用目标SDK版本为23及以上,必须在运行时请求权限:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}

onRequestPermissionsResult中处理结果:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "权限已授予!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "权限被拒绝,无法执行文件操作。", Toast.LENGTH_SHORT).show();
        }
    }
}

六、Scoped Storage适配(Android 10+)

从Android 10开始,Google鼓励开发者使用Scoped Storage,不再允许通过绝对路径访问公共目录。以下是使用MediaStore API保存图片的简单示例:

ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, "my_image.jpg");
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);

ContentResolver resolver = getContentResolver();
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

try (OutputStream os = resolver.openOutputStream(uri)) {
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
} catch (IOException e) {
    e.printStackTrace();
}

七、最佳实践与注意事项

建议说明
✅ 使用Context.getExternalFilesDir()getExternalCacheDir()这些目录不需要权限,适合存储应用专属文件。
✅ 使用Scoped Storage(MediaStore / SAF)针对Android 10及以上设备,提升兼容性。
❌ 避免硬编码路径/sdcard/,不同设备路径可能不同。
❌ 避免频繁读写大文件易造成主线程阻塞,应使用子线程或异步任务。
✅ 及时关闭流资源防止内存泄漏和IO异常。

八、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值