Android如何获取外部文件?实现自定义选择CSV文件读取及代码问题求助
Android 实现文件管理器选择CSV并读取/保存到内部存储
原代码存在的问题
- 权限申请错误:
PackageManager.PERMISSION_GRANTED是权限申请结果的常量,不能用作请求码,必须自定义请求码并处理权限回调逻辑。 - 文件路径拼接错误:
getExternalFilesDir(null)是应用专属的外部存储目录,和硬编码的绝对路径拼接后会生成无效路径,导致文件找不到。 - 未适配Scoped Storage:Android 10及以上版本启用Scoped Storage机制,直接访问公共目录(如Download)的文件需要通过存储访问框架(SAF),而非直接操作文件路径。
正确实现步骤及代码
1. 配置权限(AndroidManifest.xml)
针对不同Android版本添加必要权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <!-- 兼容Android 13以下的外部存储访问,若仅用SAF可省略,但保留可提升兼容性 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
2. MainActivity完整实现
import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import java.io.BufferedReader; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class MainActivity extends AppCompatActivity { // 文件选择请求码 private static final int CSV_FILE_REQUEST_CODE = 101; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } // 按钮点击事件:打开文件选择器 public void buttonOpenFile(View view) { // 构建打开文件的Intent,使用存储访问框架 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); // 指定仅允许选择CSV文件 intent.setType("text/csv"); // 禁止多选(按需修改) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 唤起系统文件管理器 startActivityForResult(intent, CSV_FILE_REQUEST_CODE); } // 处理文件选择结果 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CSV_FILE_REQUEST_CODE && resultCode == RESULT_OK && data != null) { // 获取选中文件的URI Uri csvUri = data.getData(); if (csvUri != null) { // 读取CSV内容 String csvContent = readCsvFile(csvUri); if (csvContent != null) { // 打印内容(替换为你的业务逻辑) System.out.println("CSV内容:\n" + csvContent); // 保存到应用内部存储 saveToInternalStorage("imported.csv", csvContent); } else { Toast.makeText(this, "读取文件失败", Toast.LENGTH_SHORT).show(); } } } } // 读取CSV文件内容 private String readCsvFile(Uri fileUri) { StringBuilder content = new StringBuilder(); try (InputStream inputStream = getContentResolver().openInputStream(fileUri); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } return content.toString(); } catch (IOException e) { e.printStackTrace(); return null; } } // 将内容保存到应用内部存储 private void saveToInternalStorage(String fileName, String content) { try (FileOutputStream fos = openFileOutput(fileName, MODE_PRIVATE)) { fos.write(content.getBytes()); Toast.makeText(this, "文件已保存至:" + getFilesDir() + "/" + fileName, Toast.LENGTH_LONG).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "保存文件失败", Toast.LENGTH_SHORT).show(); } } }
关键说明
- 存储访问框架(SAF):通过
Intent.ACTION_OPEN_DOCUMENT唤起系统文件管理器,无需直接操作文件路径,完美适配Android 10+的Scoped Storage规则。 - 文件读取:通过
getContentResolver().openInputStream(fileUri)获取文件输入流,避免直接路径访问的权限问题。 - 内部存储保存:使用
openFileOutput方法将内容写入应用专属内部存储目录,该目录无需额外权限,且仅当前应用可访问。
内容的提问来源于stack exchange,提问作者pwhited-7
相关产品推荐
相关产品推荐

