7

在我的 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. 运行 Gingerbread (2.3) 的 Nexus S (rooted)
  2. 运行 Jelly Bean (4.1.2) 的 Nexus S(无根)
  3. HTC Desire (rooted) 运行 Froyo (2.2)
  4. 运行 Froyo (2.2) 的 HTC Desire (unrooted)

然而,在运行 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 文件夹。当我将捆绑 jar 放入该文件夹时,除了 Galaxy Nexus (当应用程序第一次运行时)之外的所有手机上都可以检测到并安装它。FileInstall 没有关于无法查看目录的日志/错误。
  5. 我已经在 2 部 Galaxy Nexus 手机上进行了测试,同样的问题。

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

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

谢谢 :)

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

4

5 回答 5

2

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

我通过看到这个问题的答案得到了这个想法 -打开失败的 EBUSY 设备或资源繁忙

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

如果其他人在 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://stackoverflow.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;
    }
}
于 2013-01-08T13:56:48.450 回答
2

请使用代替

   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();
于 2012-12-19T09:15:47.913 回答
1

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

如果您无法找到可行的解决方案,也许您可​​以使用直接exec()执行 a来创建一个工作区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;   

问候。

于 2012-12-19T18:27:23.237 回答
1
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();
    }
于 2012-12-22T13:25:01.493 回答
0

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

在某些设备中,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卡应该是:

/存储/extSdCard

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

构建一个实用程序以每次获取外部可移动存储的路径

检查 SDCard 是否存在,布尔值始终为真

我怎样才能在三星和所有其他设备上获得正确的外部存储?

Android 如何使用 Environment.getExternalStorageDirectory()

于 2012-12-19T09:47:40.240 回答