IllegalArgumentException: 列 '_data' 不存在
IllegalArgumentException: column '_data' does not exist
在 Nougat 中,此功能不起作用。
String path = getRealPathFromURI(this, getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
if (cursor == null) return contentUri.getPath();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
崩溃日志:
java.lang.RuntimeException: Unable to start activity ComponentInfo{class path}: java.lang.IllegalArgumentException: column '_data' does not exist
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2659)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1473)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by java.lang.IllegalArgumentException: column '_data' does not exist
at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:333)
at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:87)
at com.package.SaveImageActivity.getRealPathFromURI()
at com.package.SaveImageActivity.onCreate()
at android.app.Activity.performCreate(Activity.java:6672)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1140)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2612)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1473)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
此功能在Android N 之前的设备中可以正常使用。我阅读了文章file:// scheme is now not allowed to be attached with Intent on targetSdkVersion 24 (Android Nougat)。但是找不到任何解决方案。所以请帮忙。
This function is working properly in devices before Android N
它适用于很少的 Uri
个值,可能没有结果(例如,对于由 MediaStore
索引的非本地文件的内容),并且可能没有可用的结果(例如,对于可移动存储上的文件)。
So please help.
使用 ContentResolver
和 openInputStream()
得到 Uri
标识的内容的 InputStream
。理想情况下,无论您要做什么,都可以直接使用该流。或者,在您控制的文件上使用 InputStream
和一些 FileOutputStream
来复制内容,然后使用该文件。
根据CommonsWare给出的答案,解决方案代码是:
public static String getFilePathFromURI(Context context, Uri contentUri) {
//copy file and send new file path
String fileName = getFileName(contentUri);
if (!TextUtils.isEmpty(fileName)) {
File copyFile = new File(TEMP_DIR_PATH + File.separator + fileName);
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
public static String getFileName(Uri uri) {
if (uri == null) return null;
String fileName = null;
String path = uri.getPath();
int cut = path.lastIndexOf('/');
if (cut != -1) {
fileName = path.substring(cut + 1);
}
return fileName;
}
public static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
if (inputStream == null) return;
OutputStream outputStream = new FileOutputStream(dstFile);
IOUtils.copyStream(inputStream, outputStream);
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
希望对您有所帮助。
IOUtils.copy 的来源来自此站点:https://www.developerfeed.com/copy-bytes-inputstream-outputstream-android/(可能需要稍微更改例外情况,但它会按需工作)
@Redturbo
我不会写评论,我写在这里
IOUtils.copyStream(inputStream, outputStream);
TEMP_DIR_PATH - 任何你的目录路径,像这样
File rootDataDir = context.getFilesDir();
File copyFile = new File( rootDataDir + File.separator + fileName + ".jpg");
//下面的代码在Android N:
private static String getFilePathForN(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getFilesDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
根据 Android R 存储框架指南进一步添加到 Vidha 的答案中,如果您不想将复制的文件永久保存到存储中:
public static String getFilePathFromURI(Context context, Uri contentUri) {
File folder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
folder = new File (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)+ "/"+ "yourAppFolderName" );
} else {
folder = new File(Environment.getExternalStorageDirectory() + "/"+ "yourAppFolderName");
}
// if you want to save the copied image temporarily for further process use .TEMP folder otherwise use your app folder where you want to save
String TEMP_DIR_PATH = folder.getAbsolutePath() + "/.TEMP_CAMERA.xxx";
//copy file and send new file path
String fileName = getFilename();
if (!TextUtils.isEmpty(fileName)) {
File dir = new File(TEMP_DIR_PATH);
dir.mkdirs();
File copyFile = new File(dir, fileName);
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
public static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
if (inputStream == null) return;
OutputStream outputStream = new FileOutputStream(dstFile);
IOUtils.copyStream(inputStream, outputStream);
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getFilename() {
// if file is not to be saved, this format can be used otherwise current fileName from Vidha's answer can be used
String ts = (new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)).format(new Date());
return ".TEMP_" + ts + ".xxx";
}
在 Nougat 中,此功能不起作用。
String path = getRealPathFromURI(this, getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
if (cursor == null) return contentUri.getPath();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
崩溃日志:
java.lang.RuntimeException: Unable to start activity ComponentInfo{class path}: java.lang.IllegalArgumentException: column '_data' does not exist
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2659)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1473)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by java.lang.IllegalArgumentException: column '_data' does not exist
at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:333)
at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:87)
at com.package.SaveImageActivity.getRealPathFromURI()
at com.package.SaveImageActivity.onCreate()
at android.app.Activity.performCreate(Activity.java:6672)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1140)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2612)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1473)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
此功能在Android N 之前的设备中可以正常使用。我阅读了文章file:// scheme is now not allowed to be attached with Intent on targetSdkVersion 24 (Android Nougat)。但是找不到任何解决方案。所以请帮忙。
This function is working properly in devices before Android N
它适用于很少的 Uri
个值,可能没有结果(例如,对于由 MediaStore
索引的非本地文件的内容),并且可能没有可用的结果(例如,对于可移动存储上的文件)。
So please help.
使用 ContentResolver
和 openInputStream()
得到 Uri
标识的内容的 InputStream
。理想情况下,无论您要做什么,都可以直接使用该流。或者,在您控制的文件上使用 InputStream
和一些 FileOutputStream
来复制内容,然后使用该文件。
根据CommonsWare给出的答案,解决方案代码是:
public static String getFilePathFromURI(Context context, Uri contentUri) {
//copy file and send new file path
String fileName = getFileName(contentUri);
if (!TextUtils.isEmpty(fileName)) {
File copyFile = new File(TEMP_DIR_PATH + File.separator + fileName);
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
public static String getFileName(Uri uri) {
if (uri == null) return null;
String fileName = null;
String path = uri.getPath();
int cut = path.lastIndexOf('/');
if (cut != -1) {
fileName = path.substring(cut + 1);
}
return fileName;
}
public static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
if (inputStream == null) return;
OutputStream outputStream = new FileOutputStream(dstFile);
IOUtils.copyStream(inputStream, outputStream);
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
希望对您有所帮助。
IOUtils.copy 的来源来自此站点:https://www.developerfeed.com/copy-bytes-inputstream-outputstream-android/(可能需要稍微更改例外情况,但它会按需工作)
@Redturbo 我不会写评论,我写在这里
IOUtils.copyStream(inputStream, outputStream);
TEMP_DIR_PATH - 任何你的目录路径,像这样
File rootDataDir = context.getFilesDir();
File copyFile = new File( rootDataDir + File.separator + fileName + ".jpg");
//下面的代码在Android N:
private static String getFilePathForN(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* * move to the first row in the Cursor, get the data,
* * and display it.
* */
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getFilesDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
根据 Android R 存储框架指南进一步添加到 Vidha 的答案中,如果您不想将复制的文件永久保存到存储中:
public static String getFilePathFromURI(Context context, Uri contentUri) {
File folder;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
folder = new File (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)+ "/"+ "yourAppFolderName" );
} else {
folder = new File(Environment.getExternalStorageDirectory() + "/"+ "yourAppFolderName");
}
// if you want to save the copied image temporarily for further process use .TEMP folder otherwise use your app folder where you want to save
String TEMP_DIR_PATH = folder.getAbsolutePath() + "/.TEMP_CAMERA.xxx";
//copy file and send new file path
String fileName = getFilename();
if (!TextUtils.isEmpty(fileName)) {
File dir = new File(TEMP_DIR_PATH);
dir.mkdirs();
File copyFile = new File(dir, fileName);
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
public static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
if (inputStream == null) return;
OutputStream outputStream = new FileOutputStream(dstFile);
IOUtils.copyStream(inputStream, outputStream);
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getFilename() {
// if file is not to be saved, this format can be used otherwise current fileName from Vidha's answer can be used
String ts = (new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)).format(new Date());
return ".TEMP_" + ts + ".xxx";
}