Android---open failed: ENOENT (No such file or directory) 错误

本文介绍了一次在Android应用中尝试创建多级目录失败的经历,并分享了解决方案。作者在尝试保存一张图片到指定路径时遇到问题,发现直接创建多级目录会导致错误。通过逐级创建目录的方法最终成功解决问题。

今天我把sd卡下面的应用目录删掉了,然后重新打开应用的时候,出现上面的错误,说是找不到该file,然后不断的加log调试,最后通过查找资料了解到新建File的时候不支持新建两级目录,也就是只能一层一层的创建。

代码如下:

/**
     * @param bitmap:图片的bitmap
     * @param src:要保存到本地的路径
     * @param bitName:要保存到本地的文件名
     * @throws IOException
     */
    private void saveBitmap(Bitmap bitmap,String src, String bitName) throws IOException
    {
        File pictureFileDir = new File(src);
        if (!pictureFileDir.exists())
        {
            pictureFileDir.mkdir();
        }
        File pictureFileDirImage =  new File(pictureFileDir.getAbsolutePath()+"/images/");
        if (!pictureFileDirImage.exists())
        {
            pictureFileDirImage.mkdir();
        }
        File picFile = new File(pictureFileDirImage.getAbsolutePath()+"/"+ bitName);
        if(!picFile.exists()){
            picFile.createNewFile();
        }
        FileOutputStream out;
        try{
            out = new FileOutputStream(picFile);
            if(bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out))
            {
                out.flush();
                out.close();
            }
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
<think>我们正在讨论的是在Android系统中处理XML数据时出现的文件未找到错误ENOENT)。根据用户提供的引用,这个问题通常与文件读写权限和Android存储策略有关。用户给出的XML数据示例是用于仓库位置的数据,但问题在于在Android中访问这个XML文件时出现了错误错误原因分析: 1. 文件确实不存在:可能是路径错误或文件未正确放置。 2. 权限问题:Android 6.0以上需要动态申请存储权限,Android 10以上还需要在AndroidManifest.xml中设置requestLegacyExternalStorage。 3. 文件路径问题:在Android中,外部存储的路径需要正确获取,并且应用需要有访问权限。 解决方案: 步骤1:检查文件是否存在 确保XML文件已经放置在设备的正确位置。如果是放在assets目录下,则应该使用AssetManager来访问;如果是放在res/raw目录下,则通过资源ID访问;如果是放在外部存储,则需要确保路径正确。 步骤2:检查权限 在AndroidManifest.xml中添加读写权限: ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 步骤3:针对Android 10及以上版本 在AndroidManifest.xml的application标签中添加: ```xml android:requestLegacyExternalStorage="true" ``` 步骤4:动态申请权限(针对Android 6.0及以上) 在运行时动态申请存储权限。 步骤5:正确获取文件路径 在Android中,外部存储的路径应该通过Environment.getExternalStorageDirectory()或Context.getExternalFilesDir()等方法来获取,避免硬编码。 示例代码(读取外部存储中的XML文件): 1. 动态申请权限(在Activity中): ```java // 检查权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE); } ``` 2. 在onRequestPermissionsResult中处理权限回调: ```java @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限被授予,可以读取文件 readXMLFile(); } else { // 权限被拒绝 Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show(); } } } ``` 3. 读取XML文件: ```java private void readXMLFile() { // 假设文件放在外部存储的根目录下,文件名为locations.xml File file = new File(Environment.getExternalStorageDirectory(), "locations.xml"); // 或者使用更推荐的方法(避免使用过时的Environment.getExternalStorageDirectory()) // File file = new File(getExternalFilesDir(null), "locations.xml"); try { FileInputStream fis = new FileInputStream(file); // 解析XML // ... 这里可以使用DOM、SAX等解析方式 fis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); Log.e("XML_READ", "File not found: " + e.getMessage()); } catch (IOException e) { e.printStackTrace(); } } ``` 注意:在Android 10及以上,即使添加了requestLegacyExternalStorage,也需要注意作用域存储(Scoped Storage)的限制。推荐使用Context.getExternalFilesDir()来访问应用私有目录,或者使用MediaStore访问公共目录。 如果XML文件是应用自带的,建议放在assets目录下,使用AssetManager读取: ```java try { InputStream is = getAssets().open("locations.xml"); // 解析XML // ... is.close(); } catch (IOException e) { e.printStackTrace(); } ``` 这样就不需要申请存储权限,因为assets是应用内部文件。 总结: 1. 检查文件路径是否正确。 2. 添加必要的权限声明和兼容性设置。 3. 动态申请权限(针对Android 6.0+)。 4. 使用合适的API获取文件路径(推荐使用应用私有目录或assets)。 根据用户提供的XML数据,如果这个XML是应用自带的,建议放在assets目录下,然后使用AssetManager读取并解析。 解析XML的代码示例(使用DOM解析): ```java private void parseXML(InputStream is) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(is); NodeList tableList = doc.getElementsByTagName("Table"); for (int i = 0; i < tableList.getLength(); i++) { Element table = (Element) tableList.item(i); String locCd = table.getElementsByTagName("LOC_CD").item(0).getTextContent(); String locNm = table.getElementsByTagName("LOC_NM").item(0).getTextContent(); // 处理数据,例如添加到列表 } } catch (Exception e) { e.printStackTrace(); } } ``` 在读取assets中的文件时调用: ```java InputStream is = getAssets().open("locations.xml"); parseXML(is); ``` 这样就能避免文件路径问题和权限问题。 如果用户需要将XML文件放在外部存储,请确保遵循Android的存储访问规范,并正确处理权限。 相关问题: §§相关问题§§ 1. 在Android中如何正确地将XML文件放入assets目录? 2. 除了DOM解析,Android中还有哪些XML解析方式? 3. 如何适配Android 11及更高版本的存储权限?</think>### 解决 Android XML 文件操作中的 `open failed: ENOENT` 错误Android 系统中处理 XML 数据时出现 `open failed: ENOENT (No such file or directory)` 错误,通常由文件路径错误或权限问题导致。以下是系统化的解决方案: --- ### 一、核心解决方案 #### 1. **权限配置(关键步骤)** 在 `AndroidManifest.xml` 中添加以下配置: ```xml <!-- 基础存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Android 10+ 兼容性配置 --> <application android:requestLegacyExternalStorage="true" ... > </application> ``` > **说明**: > - `requestLegacyExternalStorage` 是 Android 10 (API 29) 以上必需项[^3] > - Android 6.0+ 需动态申请权限(见步骤3) #### 2. **文件路径规范** ```java // ✅ 正确写法(使用 Context 获取路径) File xmlFile = new File(getExternalFilesDir(null), "locations.xml"); // ❌ 避免硬编码路径(兼容性问题) File badFile = new File("/sdcard/locations.xml"); // 可能失效 ``` **路径类型对比**: | 路径类型 | 特点 | 是否需权限 | |-------------------------|------------------------------------|------------| | `getExternalFilesDir()` | 应用私有目录,卸载时删除 | ❌ 不需要 | | `Environment.getExternalStorageDirectory()` | 公共存储,需权限 | ✅ 需要 | #### 3. **动态权限申请(Android 6.0+)** ```java // 检查权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // 申请权限 ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE ); } // 处理权限回调 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限已授予,操作文件 } } ``` --- ### 二、XML 文件操作最佳实践 #### 1. **推荐文件位置** ```java // 将 XML 文件放在 assets 目录(无需权限) InputStream is = getAssets().open("locations.xml"); // 或使用 res/raw 目录(无需权限) InputStream is = getResources().openRawResource(R.raw.locations); ``` #### 2. **XML 解析示例(DOM 解析)** ```java try (InputStream is = getAssets().open("locations.xml")) { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(is); NodeList tables = doc.getElementsByTagName("Table"); for (int i = 0; i < tables.getLength(); i++) { Element table = (Element) tables.item(i); String locCd = table.getElementsByTagName("LOC_CD").item(0).getTextContent(); String locNm = table.getElementsByTagName("LOC_NM").item(0).getTextContent(); // 处理数据... } } catch (Exception e) { Log.e("XML_PARSE", "Error reading XML: " + e.getMessage()); } ``` --- ### 三、错误排查清单 1. **检查文件是否存在**: ```java File file = new File(path); if (!file.exists()) { Log.e("FILE", "File not found: " + path); } ``` 2. **验证权限状态**: ```java if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // 权限已授予 } ``` 3. **Android 版本适配**: - Android 10+:确认 `android:requestLegacyExternalStorage="true"` - Android 11+:使用 `MANAGE_EXTERNAL_STORAGE` 或迁移至分区存储 --- ### 四、适配 Android 11+ 的存储方案 ```java // 使用 MediaStore 访问公共文件(图片/音频等) ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "locations.xml"); Uri uri = getContentResolver().insert( MediaStore.Files.getContentUri("external"), values ); // 写入 XML 数据 try (OutputStream os = getContentResolver().openOutputStream(uri)) { // 写入 XML 内容... } ``` > **注意**:Android 11 (API 30) 开始强制执行[分区存储](https://developer.android.com/training/data-storage),需使用 MediaStore 或 SAF 访问公共文件。 --- ### 总结流程图 ```mermaid graph TD A[出现 ENOENT 错误] --> B{检查权限} B -->|未授权| C[动态申请权限] B -->|已授权| D{检查文件路径} D -->|路径错误| E[使用 getExternalFilesDir] D -->|路径正确| F{Android 版本} F -->|≥ Android 10| G[添加 requestLegacyExternalStorage] F -->|≥ Android 11| H[使用 MediaStore/SAF] H --> I[操作成功] G --> I E --> I C -->|用户授权| I ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值