使用改造上传文件时出现错误(没有这样的文件或目录)
Getting error (No such file or directory) while uploading file with retrofit
我正在开发 android 应用程序,我需要 post 向服务器请求文件。
我正在使用 retrofit
来执行此操作,并且我会执行 Multipart
api 请求。
然后我使用 Intent.createChooser
来选择文件。
当我 enqueue
调用服务时出现问题。在 onFailure
我得到这个错误:
E/Upload errorrrrrr:: /document/image:77317 (No such file or directory)
但是,这是我在 onActivityResult
:
中得到的 uri 和文件路径
uri: content://com.android.providers.media.documents/document/image%3A77317
路径:/document/image:77317
然后我设置了权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
android:name="android.hardware.camera.any"
android:required="true" />
这是请求:
@Multipart
@POST("upload_document")
Call<UploadDocuments> uploadDocuments(
@Header("Authorization") String authorization,
@Part MultipartBody.Part document_name,
@Part("document_type") RequestBody document_type,
@Part("fk_id") RequestBody fk_id,
@Part("type") RequestBody type,
@Part("certificate_name") RequestBody certificate_name,
@Part("certificate_description") RequestBody certificate_description,
@Part("notes") RequestBody notes);
我该如何解决这个问题?
谢谢,
我的代码:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan_passport);
button = (Button) findViewById(R.id.btnUpload);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select File"), PICK_PHOTO_FOR_AVATAR );
}
});
}
@Override
protected void onActivityResult(int requestCode, final int resultCode, Intent data) {
if (requestCode == PICK_PHOTO_FOR_AVATAR && resultCode == Activity.RESULT_OK) {
if (data == null) {
//Display an error
return;
}
else {
Uri uri = data.getData();
path = data.getData().getPath();
if(uri != null)
uploadFile(uri);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void uploadFile(Uri fileUri) {
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile( fileUri.getPath());
// create RequestBody instance from file
final RequestBody requestFile =
RequestBody.create(
MediaType.parse("*/*"),
file
);
// MultipartBody.Part is used to send also the actual file name
final MultipartBody.Part body =
MultipartBody.Part.createFormData("document_name", file.getName(), requestFile);
// add another part within the multipart request
String document_type1 = "CV";
String fk_id1 ="2";
String type1 = "property_documents";
String certificate_name1 = "anyname";
String certificate_description1 = "anyDesc";
String notes1 = "anyNotes";
RequestBody document_type =
RequestBody.create(
okhttp3.MultipartBody.FORM, document_type1);
RequestBody fk_id =
RequestBody.create(
okhttp3.MultipartBody.FORM, fk_id1);
RequestBody type =
RequestBody.create(
okhttp3.MultipartBody.FORM, type1);
RequestBody certificate_name =
RequestBody.create(
okhttp3.MultipartBody.FORM, certificate_name1);
RequestBody certificate_description =
RequestBody.create(
okhttp3.MultipartBody.FORM, certificate_description1);
RequestBody notes =
RequestBody.create(
okhttp3.MultipartBody.FORM, notes1);
// finally, execute the request
Call<UploadDocuments> call = service.uploadDocuments(
authorization,body,document_type,
fk_id,type,certificate_name,
certificate_description,notes);
call.enqueue(new Callback<UploadDocuments>() {
@Override
public void onResponse(Call<UploadDocuments> call,Response<UploadDocuments> response) {
Log.v("Upload", "successssssssssss");
if(response.isSuccessful()) {
String status = response.body().getMessage();
if (status.equals("success")) {
String name = response.body().getData().getCertificateName();
Toast.makeText(getApplicationContext(),"done " + name,Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onFailure(Call<UploadDocuments> call, Throwable t) {
Log.e("Upload errorrrrrr:", t.getMessage());
}
});
}
编辑:
在将我的代码编辑为 Jeel 答案后,我还有其他问题,当我拍摄图像时出现问题,我收到此错误:
E/on getPath: edit profile
java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: []
at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:340)
at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:87)
at com.example.android.renteragentapp.API_Utility.FileUtil.getPath(FileUtil.java:65)
at com.example.android.renteragentapp.Activity.ScanPassportActivity.uploadFile(ScanPassportActivity.java:195)
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(hasStoragePermission(101)){
Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
if ((Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT)) {
photoURI = FileProvider.getUriForFile(ScanPassportActivity.this,
"com.example.provider",
photoFile);
//FAApplication.setPhotoUri(photoURI);
} else {
photoURI = Uri.fromFile(photoFile);
}
takePicture.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1)
{
takePicture.putExtra("android.intent.extras.LENS_FACING_FRONT", 1);
}
else {
takePicture.putExtra("android.intent.extras.CAMERA_FACING", 1);
}
startActivityForResult(takePicture, 101);
}
}
}
});
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File file = File.createTempFile(
imageFileName, //prefix
".jpg", //suffix
storageDir //directory
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = file.getAbsolutePath();
return file;
}
private boolean hasStoragePermission(int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
return false;
} else if( checkSelfPermission(Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, requestCode);
return false;
}
else {
return true;
}
} else {
return true;
}
}
我还设置了这个提供商:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.provider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
tools:replace="android:resource" />
</provider>
在从图库中 select 图片之前,您必须像下面这样请求运行时许可。
private boolean hasStoragePermission(int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
return false;
} else {
return true;
}
} else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
}
}
您的问题是 API 级别 19 及以上 (Android Kitkat),如果您为您的文件选择器打开文档提供程序,然后 Uri
您返回的结果因您选择文件的位置而异。
使用这个class:
public class FileUtil {
/*
* Gets the file path of the given Uri.
*/
@SuppressLint("NewApi")
public static String getPath(Uri uri, Context context) {
final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
// deal with different Uris.
if (needToCheckUri && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
uri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
switch (type) {
case "image":
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
break;
case "video":
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
break;
case "audio":
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
break;
}
selection = "_id=?";
selectionArgs = new String[]{
split[1]
};
}
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
MediaStore.Images.Media.DATA
};
try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) {
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
return cursor.getString(columnIndex);
}
} catch (Exception e) {
Log.e("on getPath", "Exception", e);
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
并获取如下文件:
File file = new File(FileUtil.getPath(uri, this)); // *this* here is context, which can be Activity/Fragment
注意: 如果有人需要有关代码的解释,请告诉我。
我正在开发 android 应用程序,我需要 post 向服务器请求文件。
我正在使用 retrofit
来执行此操作,并且我会执行 Multipart
api 请求。
然后我使用 Intent.createChooser
来选择文件。
当我 enqueue
调用服务时出现问题。在 onFailure
我得到这个错误:
E/Upload errorrrrrr:: /document/image:77317 (No such file or directory)
但是,这是我在 onActivityResult
:
uri: content://com.android.providers.media.documents/document/image%3A77317
路径:/document/image:77317
然后我设置了权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
android:name="android.hardware.camera.any"
android:required="true" />
这是请求:
@Multipart
@POST("upload_document")
Call<UploadDocuments> uploadDocuments(
@Header("Authorization") String authorization,
@Part MultipartBody.Part document_name,
@Part("document_type") RequestBody document_type,
@Part("fk_id") RequestBody fk_id,
@Part("type") RequestBody type,
@Part("certificate_name") RequestBody certificate_name,
@Part("certificate_description") RequestBody certificate_description,
@Part("notes") RequestBody notes);
我该如何解决这个问题? 谢谢,
我的代码:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan_passport);
button = (Button) findViewById(R.id.btnUpload);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select File"), PICK_PHOTO_FOR_AVATAR );
}
});
}
@Override
protected void onActivityResult(int requestCode, final int resultCode, Intent data) {
if (requestCode == PICK_PHOTO_FOR_AVATAR && resultCode == Activity.RESULT_OK) {
if (data == null) {
//Display an error
return;
}
else {
Uri uri = data.getData();
path = data.getData().getPath();
if(uri != null)
uploadFile(uri);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void uploadFile(Uri fileUri) {
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile( fileUri.getPath());
// create RequestBody instance from file
final RequestBody requestFile =
RequestBody.create(
MediaType.parse("*/*"),
file
);
// MultipartBody.Part is used to send also the actual file name
final MultipartBody.Part body =
MultipartBody.Part.createFormData("document_name", file.getName(), requestFile);
// add another part within the multipart request
String document_type1 = "CV";
String fk_id1 ="2";
String type1 = "property_documents";
String certificate_name1 = "anyname";
String certificate_description1 = "anyDesc";
String notes1 = "anyNotes";
RequestBody document_type =
RequestBody.create(
okhttp3.MultipartBody.FORM, document_type1);
RequestBody fk_id =
RequestBody.create(
okhttp3.MultipartBody.FORM, fk_id1);
RequestBody type =
RequestBody.create(
okhttp3.MultipartBody.FORM, type1);
RequestBody certificate_name =
RequestBody.create(
okhttp3.MultipartBody.FORM, certificate_name1);
RequestBody certificate_description =
RequestBody.create(
okhttp3.MultipartBody.FORM, certificate_description1);
RequestBody notes =
RequestBody.create(
okhttp3.MultipartBody.FORM, notes1);
// finally, execute the request
Call<UploadDocuments> call = service.uploadDocuments(
authorization,body,document_type,
fk_id,type,certificate_name,
certificate_description,notes);
call.enqueue(new Callback<UploadDocuments>() {
@Override
public void onResponse(Call<UploadDocuments> call,Response<UploadDocuments> response) {
Log.v("Upload", "successssssssssss");
if(response.isSuccessful()) {
String status = response.body().getMessage();
if (status.equals("success")) {
String name = response.body().getData().getCertificateName();
Toast.makeText(getApplicationContext(),"done " + name,Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onFailure(Call<UploadDocuments> call, Throwable t) {
Log.e("Upload errorrrrrr:", t.getMessage());
}
});
}
编辑:
在将我的代码编辑为 Jeel 答案后,我还有其他问题,当我拍摄图像时出现问题,我收到此错误:
E/on getPath: edit profile java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: [] at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:340) at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:87) at com.example.android.renteragentapp.API_Utility.FileUtil.getPath(FileUtil.java:65) at com.example.android.renteragentapp.Activity.ScanPassportActivity.uploadFile(ScanPassportActivity.java:195)
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(hasStoragePermission(101)){
Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (photoFile != null) {
if ((Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT)) {
photoURI = FileProvider.getUriForFile(ScanPassportActivity.this,
"com.example.provider",
photoFile);
//FAApplication.setPhotoUri(photoURI);
} else {
photoURI = Uri.fromFile(photoFile);
}
takePicture.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1)
{
takePicture.putExtra("android.intent.extras.LENS_FACING_FRONT", 1);
}
else {
takePicture.putExtra("android.intent.extras.CAMERA_FACING", 1);
}
startActivityForResult(takePicture, 101);
}
}
}
});
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File file = File.createTempFile(
imageFileName, //prefix
".jpg", //suffix
storageDir //directory
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = file.getAbsolutePath();
return file;
}
private boolean hasStoragePermission(int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
return false;
} else if( checkSelfPermission(Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, requestCode);
return false;
}
else {
return true;
}
} else {
return true;
}
}
我还设置了这个提供商:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.provider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
tools:replace="android:resource" />
</provider>
在从图库中 select 图片之前,您必须像下面这样请求运行时许可。
private boolean hasStoragePermission(int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
return false;
} else {
return true;
}
} else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
}
}
您的问题是 API 级别 19 及以上 (Android Kitkat),如果您为您的文件选择器打开文档提供程序,然后 Uri
您返回的结果因您选择文件的位置而异。
使用这个class:
public class FileUtil {
/*
* Gets the file path of the given Uri.
*/
@SuppressLint("NewApi")
public static String getPath(Uri uri, Context context) {
final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
// deal with different Uris.
if (needToCheckUri && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
uri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
switch (type) {
case "image":
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
break;
case "video":
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
break;
case "audio":
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
break;
}
selection = "_id=?";
selectionArgs = new String[]{
split[1]
};
}
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = {
MediaStore.Images.Media.DATA
};
try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) {
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
return cursor.getString(columnIndex);
}
} catch (Exception e) {
Log.e("on getPath", "Exception", e);
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
并获取如下文件:
File file = new File(FileUtil.getPath(uri, this)); // *this* here is context, which can be Activity/Fragment
注意: 如果有人需要有关代码的解释,请告诉我。