7

私のAndroidアプリケーションでは、SDカードに次のフォルダーを作成しようとしています。

/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があります。SDカードに問題なく他のフォルダやファイルを作成することができます。このアプリは、次の電話で正常に動作します。

  1. ジンジャーブレッド(2.3)を実行しているNexus S(ルート化)
  2. Jelly Bean(4.1.2)を実行しているNexus S(ルート化されていない)
  3. Froyo(2.2)を実行しているHTC Desire(rooted)
  4. Froyo(2.2)を実行しているHTC Desire(ルート化されていない)

ただし、Ice Cream Sandwich(4.0.4)を実行しているSamsung Galaxy Nexus電話(ルート化されていない)では、ディレクトリはゼロサイズのファイルとして作成されます。これはAstroで確認できます。presents()呼び出しはfalseを返します。

ゼロバイトのfelix-cacheファイルを示すAstro

  1. フォルダ名からわかるように、私はApacheFelixを使用しています。Felixは、キャッシュディレクトリが存在しない場合、自動的に作成します。Galaxy Nexusでは、キャッシュディレクトリを作成できないという不満が常にありました。Astroは、フォルダの代わりに0バイトのファイルを表示します。これが、Felixを初期化する前に自分でキャッシュフォルダを作成してみることにした理由です。
  2. そこで、自分でキャッシュフォルダを作成します。アプリは最初は正常に動作し、Astroでフォルダを正常に確認できます。アプリを閉じてからAstroでフォルダーを削除してからアプリを再起動すると、コードでさえ不思議なことにキャッシュディレクトリを作成できず、Astroは0バイトのファイルを表示します。
  3. Astroでは0バイトのファイルを削除できません。ただし、電話を再起動すると、フォルダは魔法のようにそこにあり、問題ありません。
  4. FileInstallを使用してOSGiComponents/installフォルダーを監視しています。バンドルjarをそのフォルダーにドロップすると、Galaxy Nexusを除くすべての電話で検出されて正常にインストールされます(アプリが最初に動作するとき)。ディレクトリを監視できないことに関するFileInstallからのログ/エラーはありません。
  5. 私はこれを2台のGalaxyNexus電話でテストしましたが、同じ問題です。

パーミッションの問題だと思いますが、それが何であるか、exists()がfalseを返す間に0バイトのファイルが作成される理由はわかりません。このファイルを作成しているのは、コードの他のどこにもありません。

何が問題になる可能性があるかについての提案はありますか?

ありがとう :)

更新:問題を特定したと思います。投稿した回答をご覧ください。

4

5 に答える 5

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 に答える
2

この問題を解決する回避策を見つけました。ファイル/ディレクトリを削除するときはいつでも、delete()を直接使用する代わりに、ファイル/フォルダの名前を変更してから、delete()します。この奇妙な回避策は問題を取り除くようです。

この質問の回答を見て、このアイデアを思いつきました-失敗したEBUSYデバイスを開くか、リソースがビジーです

しかし、なぜこれが機能するのか、そもそも何が問題を引き起こしたのかはわかりません。

他の誰かがGalaxyNexusで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 に答える
1

adbディレクトリ内のコマンドを使用してデバイスに接続し、ls -lこれについてオペレーティングシステムが報告している内容0 size file(権限など)を確認することをお勧めします。これにより、最終的に問題が明らかになる可能性があります。

実用的な解決策がわからない場合は、を使用して直接exec()実行することで回避策を作成できmkdirます。

あなたはそれをするために以下のコーブを使うことができます:

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カードは次のようになります。

/ storage / extSdCard

以下はあなたを助けるかもしれないこの問題に関するいくつかの投稿です:

毎回外部リムーバブルストレージへのパスを取得するユーティリティの構築

SDカードが存在するかどうかを確認します。ブール値は常にtrueです。

サムスンと他のすべてのデバイスで正しい外部ストレージを取得するにはどうすればよいですか?

AndroidのEnvironment.getExternalStorageDirectory()の使用方法

于 2012-12-19T09:47:40.240 に答える