私はAndroidアプリケーションで取り組んでいます。機能の1つがユーザーに開くファイルを選択できるようにする(プレーンテキスト.txtファイルを開きたい)。私はJavaと前にAndroidアプリで働いていましたが、これはKotlinを使っています、そしてそれは私の初めてKotlinを使っています。
私は現在、アプリがファイルの選択を表示していて、ユーザーに開きたいファイルをタップさせることができます。それから私はファイルオブジェクトを使ってファイルを開き、foreachlineループを実行しようとしています。しかし、何らかの理由で、ファイルピッカーから選択されたファイルを使用して、java.io.fileNotFoundException(そのようなファイルまたはディレクトリはありません)を投げます。何が問題なのかわからない、そしてファイルパスを変換するために何らかの変換をしなければならない場合は?
私の「ロード」ボタンのコード:
_val btn_load: Button = findViewById<Button>(R.id.btn_load_puzzle)
btn_load.setOnClickListener {
val intent = Intent()
.setType("*/*")
.setAction(Intent.ACTION_GET_CONTENT)
startActivityForResult(Intent.createChooser(intent, "Select a file"), 111)
}
_
ファイル選択に応答するための私の関数:
_override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Selected a file to load
if ((requestCode == 111) && (resultCode == RESULT_OK)) {
val selectedFilename = data?.data //The uri with the location of the file
if (selectedFilename != null) {
val filenameURIStr = selectedFilename.toString()
if (filenameURIStr.endsWith(".txt", true)) {
val msg = "Chosen file: " + filenameURIStr
val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT)
toast.show()
File(selectedFilename.getPath()).forEachLine {
val toast = Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT)
toast.show()
}
}
else {
val msg = "The chosen file is not a .txt file!"
val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
toast.show()
}
}
else {
val msg = "Null filename data received!"
val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
toast.show()
}
}
}
_
FileChlineループを実行するファイルオブジェクトを作成する行にFileNotFoundの例外がスローされます。
Java.lang.RuntimeException:失敗結果resultInfo {who = null、要求= 111、result = -1、data = Intent {dat = content://com.android.externalstorage.documents/0000-0000:数独パズル/hard001.txt flg = 0x1}}アクティビティ{com.example.sudokusolver/com.example.sudokusolver.mainactivity}:java.io.fileNotFoundException:/ document/0000-0000:Sudokuパズル/ hard001.txt(そのようなファイルなしまたはディレクトリ)
ファイルパスを受け取らず、Uri
を受け取りました。 ContentResolver.openInputStream()
のようなUri
ベースのAPIを使用して、その内容にアクセスする必要がありますUri
AndroidとしてApp Direct File
を基礎となるファイルへのアクセスを許可しません(それはGoogleドライブからストリーミングするか、またはこれが起こっていることを知らずにインターネットから直接ダウンロードすることもできます)。 :
_override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Selected a file to load
if ((requestCode == 111) && (resultCode == RESULT_OK)) {
val selectedFilename = data?.data //The uri with the location of the file
if (selectedFilename != null) {
contentResolver.openInputStream(selectedFilename)?.bufferedReader()?.forEachLine {
val toast = Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT)
toast.show()
}
} else {
val msg = "Null filename data received!"
val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
toast.show()
}
}
}
_
ここでは、適切なMIMEタイプを要求に渡すことで、適切なフォーマットの内容を取得することができます(テキストファイルがそのパスの一部として_.txt
_拡張子を正確に終了する必要がないため、)。
_val intent = Intent()
.setType("text/*")
.setAction(Intent.ACTION_GET_CONTENT)
startActivityForResult(Intent.createChooser(intent, "Select a file"), 111)
_
これは自動的にテキストファイルを選択できません。
URIで "msf:xxx"を取得している場合は、App CacheディレクトリにTEMPファイルを作成し、タスクが完了した後に同じファイルを削除しました。
if (id != null && id.startsWith("msf:")) {
final File file = new File(mContext.getCacheDir(), Constant.TEMP_FILE + Objects.requireNonNull(mContext.getContentResolver().getType(imageUri)).split("/")[1]);
try (final InputStream inputStream = mContext.getContentResolver().openInputStream(imageUri); OutputStream output = new FileOutputStream(file)) {
final byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
while ((read = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
output.flush();
return file;
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
_
私はこの問題を修正しました、そしてそれはMSFのための100%働いています。 :)
作業の完了後にTEMPファイルも削除してください。
private void deleteTempFile() {
final File[] files = requireContext().getCacheDir().listFiles();
if (files != null) {
for (final File file : files) {
if (file.getName().contains(Constant.TEMP_FILE)) {
file.delete();
}
}
}
}
_
ここでtemp_fileの値は "tempです"です。
URIを指定してビットマップファイルを開きます。
private Bitmap getBitmapFromUri(Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
_