Android mkdirs()创建一个零字节文件而不是文件夹

Kar*_*ran 7 android apache-felix mkdirs

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

/mnt/sdcard/OSGiComponents/admin/felix-cache/
Run Code Online (Sandbox Code Playgroud)

这是代码:

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" );
}
Run Code Online (Sandbox Code Playgroud)

我在android清单文件的清单标签下有WRITE_STORAGE_PERMISSION.我能够在SD卡上创建其他文件夹和文件而不会出现问题.该应用程序适用于以下手机:

  1. Nexus S(扎根)运行姜饼(2.3)
  2. 运行Jelly Bean的Nexus S(无根)(4.1​​.2)
  3. HTC Desire(rooted)运行Froyo(2.2)
  4. HTC Desire(无根)运行Froyo(2.2)

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

Astro显示零字节felix-cache文件

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

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

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

谢谢 :)

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

Kar*_*ran 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
        // /sf/ask/807776021/

        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;
    }
}
Run Code Online (Sandbox Code Playgroud)