如何正确保存到图片文件夹

时间:2015-10-16 19:34:03

标签: android image bitmap save mediastore

我正在尝试将用户创建的位图保存到默认的'图片'设备上的文件夹。我将从似乎是更常见的方法的选项开始:

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();
    }
}

这应该保存到'图片'文件夹,但Environment.getExternalStorageDirectory().getAbsolutePath()似乎创建了一个像file://storage/emulated/11/Pictures/这样的新文件结构,并保存图片。我也试过Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)同样的结果。但这不是默认的'图片'我的任何测试设备或模拟器上的文件夹。这导致我寻找其他方法,我发现了这个:

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();
    }
}

这实际上保存到默认文件结构,显然如下所示:content://media/external/images/media/4282。但似乎没有办法指定图像的文件名(Media.TITLE只设置标题属性,而不是实际的文件名),它保存为(看似)随机数字串。我查看MediaStore.Images.Media的{​​{3}},似乎没有任何其他变量可以设置文件名。根据{{​​3}},这似乎也不是正确的保存方式。我想知道是否有任何方法可以保存到此文件夹,同时还设置我自己的文件名。如果这种方法可以在其他设备上产生无法预料的问题。

修改 对于任何感兴趣的人,这是我目前的代码,基于@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);
}

2 个答案:

答案 0 :(得分:3)

  

这应该保存到'图片'夹

Pictures/会返回外部存储空间的根目录,而不是其中的某个位置(例如DCIM/Movies/Pictures/)。

  

我也尝试过具有相同结果的Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)

这将为您提供正确的目录,或者设备认为正确的目录(通常在外部存储中将11命名为当前用户)。

  

但是Environment.getExternalStorageDirectory()。getAbsolutePath()似乎创建了一个像这个文件的新文件结构:// storage / emulated / 11 / Pictures /

getAbsolutePath()有点不寻常,而file://不会返回带有DIRECTORY_PICTURES方案的内容,但除此之外似乎是正确的。

  

但这不是默认的'图片'我的任何测试设备或模拟器上的文件夹。

我不知道你是怎么决定的。

  

我想知道是否有任何方法可以保存到此文件夹,同时还可以设置我自己的文件名。

从第一个示例开始,切换到outputStream。然后:

  • FileOutputStream成为outputStream.getFD().sync()

  • flush()之后和close()之前致电MediaScannerConnection

  • 使用scanFile()及其MediaStore方法安排searchEmail索引图像,因此可供设备上的画廊,桌面操作系统文件管理器等使用

答案 1 :(得分:0)

使用Android 6.0 Marshmallow(API> = 23),Google引入了新的权限模型。

您必须在运行时请求权限:

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

并在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();
}

然后

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)));
}

在画廊中展示。