You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio文件选择器无法选中CSV/XLSX文件问题排查

Android文件选择器无法显示CSV/XLSX文件及解析失败问题修复

问题描述

开发一款Android应用,目标是选择CSV或Excel文件并将数据解析展示到RecyclerView,当前遇到两个核心问题:

  1. 点击上传按钮打开文件选择器后,无法显示设备中已存在的CSV/XLSX文件
  2. 移除MIME类型过滤代码后,虽能选择所有文件,但无法完成数据解析,无报错信息

测试用CSV文件内容:

Name, Price
Item1, 10
Item2, 20
Item3, 30

原问题代码

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.firebase.auth.FirebaseAuth;
import com.opencsv.CSVReader;

import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

public class AdminHome extends AppCompatActivity {
    Button logOutBtn, uploadBtn;
    FirebaseAuth mAuth;
    TextView tvEmail;
    private static final int FILE_SELECT_CODE = 1;
    private List<MenuItem> menuItemList = new ArrayList<>();
    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_admin_home);

        mAuth = FirebaseAuth.getInstance();

        tvEmail = findViewById(R.id.tvUser);
        logOutBtn = findViewById(R.id.logOutBtn);
        uploadBtn = findViewById(R.id.uploadBtn);
        String email = getIntent().getStringExtra("email");
        tvEmail.setText(email);


        uploadBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showFileChooser();
            }
        });

        logOutBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                signOut();
            }
        });
    }

    private void showFileChooser() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("*/*"); // Allow all file types
        String[] mimeTypes = {"text/csv"}; // Add CSV MIME type
        intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        try {
            startActivityForResult(Intent.createChooser(intent, "Select a File"), FILE_SELECT_CODE);

        }catch (Exception e) {
            Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
            System.out.println(e.getMessage());
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == FILE_SELECT_CODE && resultCode == RESULT_OK) {
            if(data != null) {
                Uri uri = data.getData();
                String path = uri.getPath();
                try {
                    CSVReader reader = new CSVReader(new FileReader(path));
                    String[] line;

                    while ((line = reader.readNext()) != null) {
                        String name = line[0];
                        String price = line[1];
                        menuItemList.add(new MenuItem(name, price));

                    }
                    RecyclerView recyclerView = findViewById(R.id.menu_list);
                    MenuAdapter adapter = new MenuAdapter(menuItemList);
                    recyclerView.setAdapter(adapter);
                    recyclerView.setLayoutManager(new LinearLayoutManager(this));
                    reader.close();
                }catch (Exception e) {
                    Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        finishAffinity();
    }

    public void signOut() {
        mAuth.signOut();
        Intent intent = new Intent(AdminHome.this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

问题根源及修复方案

1. 文件选择器无法显示CSV/XLSX文件

  • MIME类型覆盖不全:原代码仅添加了text/csv,但CSV可能被识别为application/csv,XLSX的标准MIME类型是application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,需补充完整:
    String[] mimeTypes = {
        "text/csv",
        "application/csv",
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    };
    intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
    
  • Intent类型兼容性:部分设备对setType("*/*")配合EXTRA_MIME_TYPES的支持不佳,可直接设置类型为支持的MIME组合:
    intent.setType("text/csv|application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    

2. 移除过滤后无法解析数据

  • Uri路径错误:uri.getPath()并非真实本地文件路径,ContentResolver的Uri需通过输入流读取,不能直接用FileReader:
    // 替换原FileReader代码
    CSVReader reader = new CSVReader(new InputStreamReader(getContentResolver().openInputStream(uri)));
    
  • 缺少文件类型校验:移除过滤后可能选择非目标文件,需在解析前判断:
    String mimeType = getContentResolver().getType(uri);
    String[] supportedTypes = {"text/csv", "application/csv", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"};
    if (!Arrays.asList(supportedTypes).contains(mimeType)) {
        Toast.makeText(this, "仅支持CSV/XLSX文件", Toast.LENGTH_SHORT).show();
        return;
    }
    
  • Excel解析支持:原代码仅处理CSV,XLSX需引入第三方库(如Apache POI),示例解析逻辑:
    XSSFWorkbook workbook = new XSSFWorkbook(getContentResolver().openInputStream(uri));
    XSSFSheet sheet = workbook.getSheetAt(0);
    // 跳过表头行
    for (int i = 1; i <= sheet.getLastRowNum(); i++) {
        Row row = sheet.getRow(i);
        if (row != null) {
            String name = row.getCell(0).getStringCellValue().trim();
            String price = String.valueOf(row.getCell(1).getNumericCellValue());
            menuItemList.add(new MenuItem(name, price));
        }
    }
    workbook.close();
    

优化后完整核心代码

private void showFileChooser() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("*/*");
    String[] mimeTypes = {
        "text/csv",
        "application/csv",
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    };
    intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    try {
        startActivityForResult(Intent.createChooser(intent, "选择CSV或XLSX文件"), FILE_SELECT_CODE);
    } catch (Exception e) {
        Toast.makeText(this, "无法打开文件选择器: " + e.getMessage(), Toast.LENGTH_LONG).show();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == FILE_SELECT_CODE && resultCode == RESULT_OK && data != null) {
        Uri uri = data.getData();
        if (uri == null) {
            Toast.makeText(this, "文件路径无效", Toast.LENGTH_SHORT).show();
            return;
        }

        String mimeType = getContentResolver().getType(uri);
        String[] supportedMimeTypes = {
            "text/csv",
            "application/csv",
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        };

        if (!Arrays.asList(supportedMimeTypes).contains(mimeType)) {
            Toast.makeText(this, "仅支持CSV和XLSX文件", Toast.LENGTH_SHORT).show();
            return;
        }

        menuItemList.clear();
        try {
            if (mimeType.contains("csv")) {
                CSVReader reader = new CSVReader(new InputStreamReader(getContentResolver().openInputStream(uri)));
                String[] line;
                reader.readNext(); // 跳过表头
                while ((line = reader.readNext()) != null) {
                    if (line.length >= 2) {
                        menuItemList.add(new MenuItem(line[0].trim(), line[1].trim()));
                    }
                }
                reader.close();
            } else if (mimeType.contains("spreadsheetml")) {
                XSSFWorkbook workbook = new XSSFWorkbook(getContentResolver().openInputStream(uri));
                XSSFSheet sheet = workbook.getSheetAt(0);
                for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                    Row row = sheet.getRow(i);
                    if (row != null) {
                        String name = row.getCell(0) != null ? row.getCell(0).getStringCellValue().trim() : "";
                        String price = row.getCell(1) != null ? String.valueOf(row.getCell(1).getNumericCellValue()) : "";
                        menuItemList.add(new MenuItem(name, price));
                    }
                }
                workbook.close();
            }

            RecyclerView recyclerView = findViewById(R.id.menu_list);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));
            recyclerView.setAdapter(new MenuAdapter(menuItemList));
            Toast.makeText(this, "解析成功,共" + menuItemList.size() + "条数据", Toast.LENGTH_SHORT).show();

        } catch (Exception e) {
            Toast.makeText(this, "解析失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
}

额外注意事项

  • 若需解析XLSX,需在build.gradle(app)中添加Apache POI依赖:
    implementation 'org.apache.poi:poi:5.2.3'
    implementation 'org.apache.poi:poi-ooxml:5.2.3'
    
  • Android 10及以上无需申请READ_EXTERNAL_STORAGE权限,旧版本需在Manifest中声明并动态申请。

内容的提问来源于stack exchange,提问作者Naak Mukka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 12:57:03