How To Properly Save To The Pictures Folder

匿名 (未验证) 提交于 2019-12-03 02:31:01

问题:

I am trying to save a bitmap that is created by the user to the default 'Pictures' folder on the device. I will start with the option that seems to be the more common method:

public void saveImageToExternalStorage(String filename, Bitmap image) {     String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;     try {         File directory = new File(path);         if (!directory.exists()) {             directory.mkdirs();         }          File file = new File(directory, filename + ".jpeg");         file.createNewFile();          OutputStream outputStream = new FileOutputStream(file);         image.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);          outputStream.flush();         outputStream.close();     } catch (IOException exception) {         exception.printStackTrace();     } }

This is supposed to save to the 'Pictures' folder, but Environment.getExternalStorageDirectory().getAbsolutePath() seems to create a new file structure like this file://storage/emulated/11/Pictures/ and save the picture to that. I have also tried Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) with the same result. But this is not the default 'Pictures' folder on any of my test devices or emulators. Which led me to look for other methods, and I found this:

public void saveImageToExternalStorage(String filename, Bitmap image) {     try {         ContentValues values = new ContentValues();         values.put(MediaStore.Images.Media.TITLE, filename);         values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());         values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");          Uri filepath = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);         OutputStream outputStream = getContentResolver().openOutputStream(filepath);          image.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);         outputStream.close();     } catch (IOException exception) {         exception.printStackTrace();     } }

This actually saves to the default file structure, which apparently looks like this: content://media/external/images/media/4282. But there seems to be no way to specify the filename of the image (Media.TITLE just sets the title attribute, not the actual filename), it saves as a (seemingly) random string of numbers. I looked at the API Guide for MediaStore.Images.Media and there does not seem to be any other variable that would set the filename. This also does not seem to be the correct way of saving, according to the Android Developer Guides. I would like to know if there is any way of saving to this folder, while also setting my own filename. And if this method could produce unforeseen problems on other devices.

EDIT: For anyone interested this is my current code, based on the answer by @CommonsWare:

public void saveImageToExternalStorage(Context context, String filename, Bitmap image) throws IOException {     File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);     File file = new File(directory, filename + ".jpeg");      FileOutputStream outputStream = new FileOutputStream(file);     mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);      outputStream.flush();     outputStream.getFD().sync();     outputStream.close();      MediaScannerConnection.scanFile(context, new String[] {file.getAbsolutePath()}, null, null); }

回答1:

This is supposed to save to the 'Pictures' folder

getExternalStorageDirectory() returns the root of external storage, not some location inside of it (e.g., Pictures/, DCIM/, Movies/).

I have also tried Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) with the same result

That will give you the proper directory, or whatever the device thinks the proper directory is (usually named Pictures/ in external storage for whoever the current user is).

but Environment.getExternalStorageDirectory().getAbsolutePath() seems to create a new file structure like this file://storage/emulated/11/Pictures/

The 11 is a bit unusual, and getAbsolutePath() does not return something with a file:// scheme, but otherwise that seems about right.

But this is not the default 'Pictures' folder on any of my test devices or emulators.

I do not know how you have determined this.

I would like to know if there is any way of saving to this folder, while also setting my own filename.

Start with your first sample, switching to DIRECTORY_PICTURES. Then:

  • have outputStream be a FileOutputStream

  • call outputStream.getFD().sync() after flush() and before close()

  • use MediaScannerConnection and its scanFile() method to arrange for the MediaStore to index the image, so it is available to on-device galleries, desktop OS file managers, etc.



回答2:

With Android 6.0 Marshmallow (API >= 23), Google introduced a new permission model.

You have to request permission at run-time:

String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE}; requestPermissions(permissions, WRITE_REQUEST_CODE);

and handle the result in onRequestPermissionsResult(),

File path = Environment.getExternalStoragePublicDirectory(     Environment.DIRECTORY_PICTURES); File file = new File(path, "db.JPG"); try {     file.createNewFile(); } catch (IOException e) {     Toast.makeText(this.getApplicationContext(),     "createNewFile:"+e.toString(),     Toast.LENGTH_LONG).show(); }

then

if (Build.VERSION.SDK_INT < 19) {     sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,     Uri.parse("file://" + filename))); } else {     sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,     Uri.parse("file://" + filename))); }

to show in the gallery.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!