【问题标题】:Android mkdirs() creates a zero byte file instead of a folderAndroid mkdirs() 创建一个零字节文件而不是文件夹
【发布时间】:2026-02-12 20:55:01
【问题描述】:

在我的 android 应用程序中,我试图在 sdcard 上创建以下文件夹:

/mnt/sdcard/OSGiComponents/admin/felix-cache/

代码如下:

File cacheDir = 
    new File( Environment.getExternalStorageDirectory().getAbsolutePath() + 
              "/OSGiComponents/admin/felix-cache/" );
// Create the folder
cacheDir.mkdirs();
// Check if it exists
if ( ! cacheDir.exists() ) {
    Log.e ( "Debug" , "Cache directory cannot be created" );
}

我在 android 清单文件的清单标记下有 WRITE_STORAGE_PERMISSION。我可以在 sdcard 上创建其他文件夹和文件而不会出现问题。 该应用可在以下手机上正常运行:

  1. Nexus S(root)运行 Gingerbread (2.3)
  2. Nexus S(无根)运行 Jelly Bean (4.1.2)
  3. HTC Desire (root) 运行 Froyo (2.2)
  4. HTC Desire(无根)运行 Froyo (2.2)

但是,在运行 Ice Cream Sandwich (4.0.4) 的三星 Galaxy Nexus 手机(无根)上,该目录被创建为一个零大小的文件,可以在 Astro 中看到。 exists() 调用返回 false。

  1. 从文件夹名称可以看出,我使用的是 Apache Felix。如果缓存目录不存在,Felix 会自动创建它。在 Galaxy Nexus 上,它总是抱怨无法创建缓存目录。 Astro 显示的是 0 字节文件而不是文件夹。这就是为什么我决定在初始化 Felix 之前自己尝试创建缓存文件夹的原因。
  2. 所以,我自己创建了缓存文件夹。该应用程序第一次运行良好,我可以在 Astro 中看到该文件夹​​。如果我关闭应用程序,然后删除Astro中的文件夹,然后重新启动应用程序,即使我的代码也神秘地无法创建缓存目录,Astro显示一个0字节的文件。
  3. 0 字节文件无法在 Astro 中删除。但是,当我重新启动手机时,该文件夹神奇地存在并且正常。
  4. 我使用 FileInstall 来监视 OSGiComponents/install 文件夹。当我将捆绑 jar 放入该文件夹时,除了 Galaxy Nexus (当应用程序第一次运行时)之外,所有手机都可以检测到并安装它。 FileInstall 没有关于无法查看目录的日志/错误。
  5. 我已经在 2 部 Galaxy Nexus 手机上测试过,同样的问题。

我怀疑这是一个权限问题,但我不确定它是什么,以及为什么在 exists() 返回 false 时会创建一个 0 字节文件。我没有在代码中的其他任何地方创建此文件。

关于可能是什么问题的任何建议?

谢谢:)

更新:我想我已经确定了问题,请查看我发布的答案。

【问题讨论】:

  • public static String FOLDER = Environment.getExternalStorageDirectory().getPath()+"/folder/";文件屏幕路径 = 新文件(文件夹);屏幕路径.mkdirs();这可能有效。
  • 谢谢,但不幸的是仍然出现同样的问题:(我想我已经确定了这个问题,我在下面发布了一个答案。

标签: android apache-felix mkdirs


【解决方案1】:

请使用代替

   File cacheDir = new File( Environment.getExternalStorageDirectory().getAbsolutePath() + 
          "/OSGiComponents/admin/felix-cache/" );
      cacheDir.mkdirs();

  File cacheDir = 
new File( Environment.getExternalStorageDirectory().getAbsolutePath() + 
          "/OSGiComponents/admin/felix-cache" );
     cacheDir.mkdir();

【讨论】:

  • 谢谢,但是我在删除最后一个斜杠并将 mkdirs() 更改为 mkdir() 或这些更改的任何组合时遇到了同样的问题。如果我的理解是正确的,因为这个目录树最初在手机上是不存在的,所以必须使用 mkdirs() 而不是 mkdir()。此外,Felix 在内部也使用 mkdirs()。
  • 一次请删除getAbsolutePath()并检查一次
  • 我仍然遇到同样的问题。
  • 沃利在哪里?它是尾随的/
【解决方案2】:

我找到了解决此问题的解决方法。每当我删除文件/目录时,我不是直接使用 delete(),而是重命名文件/文件夹,然后 delete() 它。这种奇怪的解决方法似乎可以解决问题。

看到这个问题的答案,我有了这个想法 - Open failed EBUSY device or Resource busy

但是,我不确定为什么会这样,或者首先是什么导致了问题。

如果其他人在 Galaxy Nexus 上使用 Felix 并遇到同样的问题,只需更改 Felix 源代码,如下所示:

org.apache.felix.framework.util.SecureAction.java:

public boolean deleteFile(File target)
{
    if (System.getSecurityManager() != null)
    {
        try
        {
            Actions actions = (Actions) m_actions.get();
            actions.set(Actions.DELETE_FILE_ACTION, target);
            return ((Boolean) AccessController.doPrivileged(actions, m_acc))
                .booleanValue();
        }
        catch (PrivilegedActionException ex)
        {
            throw (RuntimeException) ex.getException();
        }
    }
    else
    {
        // Solution: Rename before deleting
        // https://*.com/questions/11539657/open-failed-ebusy-device-or-resource-busy

        File to = new File(target.getAbsolutePath() + System.currentTimeMillis());
        boolean renameStatus = target.renameTo(to);
        boolean deleteStatus = to.delete();
        boolean returnStatus = ( renameStatus && deleteStatus );

        // Debug SecureAction
        //boolean returnStatus = target.delete();
        Log.e ( "SecureAction" , "Deleting " + target + " delete(): " + returnStatus );
        return returnStatus;
    }
}

【讨论】:

    【解决方案3】:

    我建议您使用adb 连接到设备,并在目录中使用命令ls -l,以查看操作系统报告有关此0 size file 的内容(权限等)。这最终可以为这个问题带来一些启示。

    如果您找不到可行的解决方案,也许您可​​以使用exec() 直接执行mkdir

    您可以使用下面的 cobe 来做到这一点:

    public static boolean execCmd(String command, ArrayList<String> results){
        Process process;
        try {
            process = Runtime.getRuntime().exec(new String [] {"sh", "-c", command});
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } 
    
        int result;
        try {
            result = process.waitFor();
        } catch (InterruptedException e1) {
            e1.printStackTrace();
            return false;
        }
    
        if(result != 0){ //error executing command
            Log.d("execCmd", "result code : " + result);
            String line; 
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); 
            try {
                while ((line = bufferedReader.readLine()) != null){
                    if(results != null) results.add(line);
                    Log.d("execCmd", "Error: " + line);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            return false;
        }
    
        //Command execution is OK
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 
    
        String line; 
        try {
            while ((line = bufferedReader.readLine()) != null){
                if(results != null) results.add(line);
                Log.d("execCmd", line);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    

    使用它:

    boolean res= execCmd("mkdir "+ Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents", results);
    if(!res) return error;   
    
    res= execCmd("mkdir "+ Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents/admin", results);
    if(!res) return error;   
    
    res= execCmd("mkdir "+ Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSGiComponents/admin/felix-cache", results);
    if(!res) return error;   
    

    问候。

    【讨论】:

    • 感谢您的详细回复。我尝试了你的解决方法,但不幸的是它仍然给出了同样的问题:(
    • 我今天做了一些调试,并确定了导致问​​题的文件操作顺序。我已经对此发布了一个问题 - Related Question
    【解决方案4】:
    String root = Environment.getExternalStorageDirectory()
                .getAbsolutePath()+"/OSGiComponents/admin/felix-cache";
        File myDir = new File(root);
    
        String fname = "Image Name as you want";
        File file = new File(myDir, fname);
        if (file.exists())
            file.delete();
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
            out.flush();
            out.close();
    
        } catch (Exception e) {
            e.printStackTrace();
        }
    

    【讨论】:

    • @Yogesh - 谢谢,但我正在尝试创建一个目录,而不是一个文件。
    【解决方案5】:

    虽然不是直接回答您的问题,但下面提到的信息可能会对您有所帮助:

    在某些设备中,Environment.getExternalStorageDirectory().getAbsolutePath() 不一定反映实际的外部 sd 卡路径。有时它代表内部存储。

    例如在 Galaxy Note 2 中:

    Log.i(TAG,Environment.getExternalStorageDirectory().getAbsolutePath()); 
    

    将打印

    12-19 17:35:11.366: E/sample.Examples(10420): /storage/sdcard0

    同时实际的外置sd卡应该是:

    /storage/extSdCard

    以下是有关此问题的几篇文章,可能会对您有所帮助:

    Building a Utility to get the path to External Removable storage every time

    Check if the SDCard is present, boolean is always true

    How could i get the correct external storage on Samsung and all other devices?

    Android how to use Environment.getExternalStorageDirectory()

    【讨论】:

    • 感谢您提供的信息,我将查看您的链接,看看是否有任何链接可以解决问题。
    • 我浏览了这些链接,但在我的手机上,/mnt/sdcard 是正确的,它指的是“外部”内部闪存。另外,缓存在哪里创建也没有关系,只要它被创建并且可以被写入即可。
    最近更新 更多