一部のデバイスでストレージにアクセスすると、非常に奇妙な問題が発生します。アプリは私のテストデバイス(Nexus 4および7、Samsung GS5)で動作します。 Android 4.4.2を実行しているすべてのデバイス。しかし、私はユーザーから、アプリがストレージ(内部ストレージでもSDカードでもない)に書き込むことができないというメールを多く受け取りました。ユーザーフィードバックから受け取ったログファイルから、問題は次のコードであることがわかります。
try {
if (fStream == null) {
fStream = new FileOutputStream(filename, true);
}
fStream.write(data, 0, bytes);
return;
} catch (IOException ex) {
ex.printStackTrace();
}
行fStream = new FileOutputStream(filename、true);で例外をスローします。 FileOutputStreamを作成するとき。
スタックログは次のとおりです。
W/System.err( 8147): Caused by: Java.io.FileNotFoundException: /storage/emulated/0/my_folder/test_file_name.png: open failed: EACCES (Permission denied)
w/System.err( 8147): at libcore.io.IoBridge.open(IoBridge.Java:409)
W/System.err( 8147): at Java.io.FileOutputStream.<init>(FileOutputStream.Java:88)
W/System.err( 8147): at Java.io.FileOutputStream.<init>(FileOutputStream.Java:128)
W/System.err( 8147): at myapp.save(SourceFile:515)
W/System.err( 8147): ... 8 more
W/System.err( 8147): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
W/System.err( 8147): at libcore.io.Posix.open(Native Method)
W/System.err( 8147): at libcore.io.BlockGuardOs.open(BlockGuardOs.Java:110)
W/System.err( 8147): at libcore.io.IoBridge.open(IoBridge.Java:393)
W/System.err( 8147): ... 11 more
AndroidManifest.xmlでは、次の権限が宣言されています。
<uses-sdk Android:minSdkVersion="14" Android:targetSdkVersion="19"/>
<uses-permission Android:name="Android.permission.INTERNET"/>
<uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission Android:name="Android.permission.ACCESS_WIFI_STATE"/>
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/>
ユーザーがSDカードで正しいアプリのプライベートを使用していることを確認しました。さらに奇妙なのは、内部ストレージへの書き込みも失敗することです。読み取りと書き込みの両方のアクセス許可がある場合、どのようになりますか?ユーザーは、その時点ではデバイスをPCに接続していないと言います。
更新
FileOutputStreamのオープンとクローズを頻繁に呼び出しているため、ある時点でFileNotFoundExceptionがスローされます。スレッドの問題のようです。
私はしばらく前に同様の問題に遭遇しました。
問題は2つの異なる領域にある可能性があります。書き込み先のファイルの作成方法、または電話に依存するという点で書き込み方法に欠陥がある可能性があります。
SDカードの特定の場所にファイルを書き込む場合は、環境変数を使用してみてください。彼らは常に有効な場所を指す必要があります。ダウンロードフォルダーに書き込む例を次に示します。
Java.io.File xmlFile = new Java.io.File(Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
+ "/Filename.xml");
ファイルをアプリケーションの内部ストレージに書き込む場合。この例を試してください:
Java.io.File xmlFile = new Java.io.File((getActivity()
.getApplicationContext().getFileStreamPath("FileName.xml")
.getPath()));
個人的には、ファイルへのストリーミングを処理するために外部ライブラリに依存しています。これはまだ失敗していません。
org.Apache.commons.io.FileUtils.copyInputStreamToFile(is, file);
書き込みコマンドの失敗でデータを1回も失ったため、IOの負荷を軽減するために、よく知られたテスト済みのライブラリに依存しています。
ファイルが大きい場合は、バックグラウンドでIOを実行するか、コールバックを使用することもできます。
既に環境変数を使用している場合は、アクセス許可の問題である可能性があります。以下のジャスティンフィードラーの回答をご覧ください。
API 23+の場合、既にマニフェストに含まれている場合でも、読み取り/書き込み権限を要求する必要があります。
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
/**
* Checks if the app has permission to write to device storage
*
* If the app does not has permission then the user will be prompted to grant permissions
*
* @param activity
*/
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so Prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
AndroidManifest.xml
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
私の場合、私は間違ったケースを持っていました
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
Android.permission
は小文字である必要があり、ソースでは文字列全体が大文字でした。
私も同じ問題に直面しました。多大な労力を費やした後、私の場合の問題点を見つけました。デバイスがUSBケーブルでコンピューターに接続されました。 USB接続には、マスストレージ、メディアデバイス(MTP)、カメラ(PTP)などのタイプがあります。接続タイプは「マスストレージ」で、これが問題の原因でした。接続タイプを変更すると、問題は解決しました。
Androidデバイスのファイルシステムにアクセスするときは常に覚えておいてください:-
大量のストレージとしてコンピューター/ PCに接続しないでください。
まず、次のような権限を付与または確認します
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE"/>
これらの2つの許可がOKの場合、出力ストリームが正しい形式であることを確認してください。
例:
FileOutputStream fos=new FileOutputStream(Environment.getExternalStorageDirectory()+"/rahul1.jpg");
私の場合、それは権限の問題でした。問題は、Android 4.0.4を搭載したデバイスで、エラーや例外なしでファイルにアクセスできることです。また、Android 5.1のデバイスでは、ACCESS例外で失敗しました(オープンに失敗しました:EACCES(許可が拒否されました))。マニフェストファイルにフォロー許可を追加して処理しました。
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE"/>
だから、OSバージョンのパーミッション管理の違いが失敗の原因だと思います。
同じ問題にぶつかり、マニフェストで宣言していても、実行時にアクセス許可を要求する必要があることがわかりました。ジャスティン・フィードラーの答えと同じように。
これに関する公式ドキュメントはこちらです: https://developer.Android.com/training/permissions/requesting.html
私の実装は、v4フラグメントのonRequestPermissionsResultメソッドも実装して、許可要求応答を処理するというJustin Fiedlerの回答とは少し異なります。
public static final int REQUEST_EXTERNAL_PERMISSION_CODE = 666;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static final String[] PERMISSIONS_EXTERNAL_STORAGE = {
READ_EXTERNAL_STORAGE,
WRITE_EXTERNAL_STORAGE
};
public boolean checkExternalStoragePermission(Activity activity) {
if (Android.os.Build.VERSION.SDK_INT < Android.os.Build.VERSION_CODES.JELLY_BEAN) {
return true;
}
int readStoragePermissionState = ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
int writeStoragePermissionState = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
boolean externalStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED &&
writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
if (!externalStoragePermissionGranted) {
requestPermissions(PERMISSIONS_EXTERNAL_STORAGE, REQUEST_EXTERNAL_PERMISSION_CODE);
}
return externalStoragePermissionGranted;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_PERMISSION_CODE) {
if (checkExternalStoragePermission(getActivity())) {
// Continue with your action after permission request succeed
}
}
}
}
私の場合、Android:isolatedProcess="true"
のservice
にオプションAndroidManifest.xml
を使用しました。
削除するとすぐにエラーが消えました...
アプリターゲティングAndroid Qには、デフォルトで外部ストレージへのフィルタービューが与えられます。そのための簡単な修正は、AndroidManifest.xmlに次のコードを追加することです。
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application Android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
詳しくはこちらをご覧ください: https://developer.Android.com/preview/privacy/scoped-storage
私は同じ問題を受け取りましたが、時々、最も難しい問題が簡単な答えを得ることがあります。
私はマニフェストのアクセス許可を再確認し、そこに私のアクセス許可の恥を書きませんでした!!!
また、自分のやり方で解決することがわかりました。
アプリを起動する前に、ファイルエクスプローラーにルートを付与し、アプリの終了時に書き込み/読み取りの許可を無効にしませんでした。
すべての権限をリセットするためにデバイスを再構築した間、私のアプリは外部メモリを使用できません。
クライアントがAndroid 6.0を使用している場合、Androidが(Marshmallow)の新しい 許可モデル を追加しました。
トリック:バージョン22以下をターゲットにしている場合、アプリケーションはインストール時にMarshmallow以下のOSを実行しているデバイスと同様にすべての権限を要求します
私の場合、問題は、同じIPアドレスを使用している別のデバイスと競合する静的なWIFI設定でした。