Android模拟器相册图片上传时出现ENOENT目录不存在错误求助
解决Android模拟器相册图片上传服务器的ENOENT文件不存在错误
错误日志:
D/Main: /document/1AE6-2C19:Download/food2.jpg: open failed: ENOENT (No such file or directory)
在Android模拟器中从相册选取图片上传至服务器时触发该错误,已尝试Stack Overflow同类问题解决方案但未解决。
问题根源
你直接把Content URI的字符串当成真实文件路径来创建RequestBody了。相册返回的content://开头的URI是系统提供的内容访问标识,并非文件系统中的真实路径,用这个字符串创建请求体必然导致系统找不到对应文件,抛出ENOENT错误。
修正方案
一、重构上传逻辑,通过ContentResolver读取文件
放弃直接使用URI字符串,改为通过ContentResolver打开文件输入流,将流转换为RequestBody。修改uploadProfileImage方法及添加辅助工具方法:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) { // 直接保留Uri对象,不要转成字符串 profileImageUri = data.getData(); try { Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), profileImageUri); profilePicture.setImageBitmap(bitmap); } catch (IOException e) { e.printStackTrace(); } } } public void uploadProfileImage(){ if (profileImageUri == null) { Toast.makeText(this, "请先选择图片", Toast.LENGTH_SHORT).show(); return; } try { // 获取文件MIME类型,没有则默认设为JPEG String mimeType = getContentResolver().getType(profileImageUri); mimeType = mimeType == null ? "image/jpeg" : mimeType; // 通过ContentResolver读取文件字节流,创建RequestBody RequestBody requestBody = RequestBody.create( MediaType.parse(mimeType), getBytesFromUri(profileImageUri) ); // 从Uri中提取原文件名 String fileName = getFileNameFromUri(profileImageUri); MultipartBody.Part body = MultipartBody.Part.createFormData("file", fileName, requestBody); Call<ImageDto> imageDtoCall = BaseUrlClient .getInstance().getApi().uploadProfileImage(body); imageDtoCall.enqueue(new Callback<ImageDto>() { @RequiresApi(api = Build.VERSION_CODES.O) @Override public void onResponse(Call<ImageDto> call, Response<ImageDto> response) { if (response.code() == 201){ assert response.body() != null; Log.d("Main","The image url is "+response.body().getDownloadUrl()); //createPatient(response.body().getDownloadUrl()); }else { Log.d("Main","Response code is "+response.code()); Toast.makeText(PatientRegistrationActivity.this, "图片上传失败,请重试", Toast.LENGTH_SHORT).show(); try { Log.d("Main",response.errorBody().string()); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<ImageDto> call, Throwable t) { Log.d("Main",t.getMessage()); Toast.makeText(PatientRegistrationActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show(); } }); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "读取图片失败", Toast.LENGTH_SHORT).show(); } } // 将Uri对应的文件转为字节数组 private byte[] getBytesFromUri(Uri uri) throws IOException { InputStream inputStream = getContentResolver().openInputStream(uri); ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int len; while ((len = inputStream.read(buffer)) != -1) { byteBuffer.write(buffer, 0, len); } inputStream.close(); return byteBuffer.toByteArray(); } // 从Uri中提取文件名 private String getFileNameFromUri(Uri uri) { String fileName = "profile_image.jpg"; Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null && cursor.moveToFirst()) { int nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME); if (nameIndex != -1) { fileName = cursor.getString(nameIndex); } cursor.close(); } return fileName; }
二、确认权限配置
在AndroidManifest.xml中添加必要权限,并在运行时动态申请:
<!-- Android 13及以上读取图片权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Android 13以下版本读取存储权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
三、额外检查点
- 确保模拟器的虚拟存储配置正常,相册中的测试文件确实存在
- 避免在任何环节将
Uri转为字符串存储,全程保留Uri对象进行操作
内容的提问来源于stack exchange,提问作者Ukeme Elijah
相关产品推荐
相关产品推荐

