将位图保存到应用程序文件夹

问题描述 投票:0回答:6

当我的应用程序首次启动时,它允许用户选择个人资料图片。这可以通过立即拍照或从图库中选择来完成。

用户获取图片后,必须将其保存在设备的内部存储中,并将在应用程序中用作用户的个人资料图片。

这个过程工作正常,用户获取图片,并在保存之前显示在图像视图中。但要将图像保存在内部存储中,我遇到了一些麻烦。我尝试了几种方法来做到这一点,其中大多数似乎都有效。但是当我尝试它们时,图片没有被保存,或者至少我没有找到保存它的文件夹。

我尝试过这3种方式:

第一:

File directory = getDir("profile", Context.MODE_PRIVATE);
File mypath = new File(directory, "thumbnail.png");

FileOutputStream fos = null;
try {
    fos = new FileOutputStream(mypath);
    mybitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
    fos.close();
} catch (Exception e) {
    e.printStackTrace();
}

第二:

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
mybitmap.compress(Bitmap.CompressFormat.PNG, 90, bytes);

FileOutputStream fos = null;
try {
    fos = openFileOutput("thumbnail.png", Context.MODE_PRIVATE);
    fos.write(bytes.toByteArray());
    fos.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

第三:

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
mybitmap.compress(Bitmap.CompressFormat.PNG, 90, bytes);

File fileWithinMyDir = new File(getFilesDir(), "thumbnail.png");
try {
    FileOutputStream fos = new FileOutputStream(fileWithinMyDir);
    fos.write(bytes.toByteArray());
    fos.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

据说,图像保存在路径:

android/data/AppName/app_data/
中,但那里没有创建文件夹。无论如何,我查看了其他文件夹,但什么也没有。

编辑-

在第一个方法中,我看到它抛出了异常:

E/SAVE_IMAGE﹕ /data/data/com.example.myapp/app_profile/thumbnail.png: open failed: EISDIR (Is a directory)
java.io.FileNotFoundException: /data/data/com.example.myapp/app_profile/thumbnail.png: open failed: EISDIR (Is a directory)
Caused by: libcore.io.ErrnoException: open failed: EISDIR (Is a directory)
android bitmap
6个回答
8
投票

尝试了几件事后,这最终对我有用:

ContextWrapper cw = new ContextWrapper(getApplicationContext());
File directory = cw.getDir("profile", Context.MODE_PRIVATE);
if (!directory.exists()) {
    directory.mkdir();
}
File mypath = new File(directory, "thumbnail.png");

FileOutputStream fos = null;
try {
    fos = new FileOutputStream(mypath);
    resizedbitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
    fos.close();
} catch (Exception e) {
    Log.e("SAVE_IMAGE", e.getMessage(), e);
}

基本上就是检查目录(而不是文件)是否存在,如果不存在,则使用 mkdir() 创建它。


4
投票

您可以使用此

ImageSaver
类将位图图像保存到您的应用程序文件夹。 图像保存器类代码如下:

public class ImageSaver {
    private String directoryName = "images";
    private String fileName = "image.png";
    private Context context;
    private File dir;
    private boolean external=false;

    public ImageSaver(Context context) {
        this.context = context;
    }

    public ImageSaver setFileName(String fileName) {
        this.fileName = fileName;
        return this;
    }

    public ImageSaver setExternal(boolean external) {
        this.external = external;
        return this;
    }
   
    public ImageSaver setDirectory(String directoryName) {
        this.directoryName = directoryName;
        return this;
    }

    public void save(Bitmap bitmapImage) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(createFile());
            bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @NonNull
    private File createFile() {
        File directory;
        if (external) {
            directory = getAlbumStorageDir(directoryName);
            if (!directory.exists()){
                directory.mkdir();
            }
        } else {
            directory = new File(context.getFilesDir()+"/"+directoryName);
            if (!directory.exists()){
                directory.mkdir();
            }
        }

        return new File(directory, fileName);
    }

    private File getAlbumStorageDir(String albumName) {
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), albumName);
        if (!file.mkdirs()) {
            Log.e("ImageSaver", "Directory not created");
        }
        return file;
    }

    public static boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }

    public static boolean isExternalStorageReadable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state) ||
                Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
    }

    public Bitmap load() {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(createFile());
            return BitmapFactory.decodeStream(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public boolean deleteFile() {
        File file = createFile();
        return file.delete();
    }
}

然后,在您从服务器获取位图的活动中(通过使用 Glide 或 Picasso,但您可以使用任何方法),您应该在调用

setExternal
之前设置
.setDirectory

Bitmap bitmap=........//bitmap from code
    new ImageSaver(this)
            .setFileName("filename.jpg")
             .setExternal(false)//image save in external directory or app folder default value is false
            .setDirectory("dir_name")
            .save(bitmap); //Bitmap from your code

2
投票

了解您的要求。下面粘贴了一些我测试过并正在运行的代码。基本上从相机获取图像并将其保存在应用程序存储中。请仔细阅读。希望这有帮助。干杯..

//用于保存图像...

private String saveToInternalSorage(Bitmap bitmapImage) {
    ContextWrapper cw = new ContextWrapper(getApplicationContext());
    File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
    // Create imageDir
    File mypath = new File(directory, "profile.jpg");

    FileOutputStream fos = null;
    try {

        fos = new FileOutputStream(mypath);

        // Use the compress method on the BitMap object to write image to
        // the OutputStream
        bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
        fos.close();
        Editor editor = sharedpreferences.edit();
        editor.putString("saved", "na");
        editor.commit(); 

    } catch (Exception e) {
        e.printStackTrace();
    }
    return directory.getAbsolutePath();
}

//..从存储加载图像

private void loadImageFromStorage(String path) {

    try {
        ContextWrapper cw = new ContextWrapper(getApplicationContext());
        File path1 = cw.getDir("imageDir", Context.MODE_PRIVATE);
        File f = new File(path1, "profile.jpg");
        Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
        ImageView img = (ImageView) findViewById(R.id.viewImage);
        img.setImageBitmap(b);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

}

0
投票

好吧,如果该文件夹不存在,则需要创建该文件夹。

尝试运行此代码,看看它是否可以解决您的问题:

File parentDestination = saveFile.getParentFile();
    if (!parentDestination.exists()) {
        parentDestination.mkdirs(); //make all the directory structures needed
    }

0
投票

试试这个...

您应该使用 Bitmap.compress() 方法将位图保存为文件。它将压缩(如果使用的格式允许)您的图片并将其推送到 OutputStream 中。

这里是通过 getImageBitmap(myurl) 获取的 Bitmap 实例的示例,可以将其压缩为 JPEG,压缩率为 85% :

String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path, "FitnessGirl"+Contador+".jpg"); // the File to save to
fOut = new FileOutputStream(file);

Bitmap pictureBitmap = getImageBitmap(myurl); // obtaining the Bitmap
pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut); // saving the Bitmap to a file compressed as a JPEG with 85% compression rate
fOut.flush();
fOut.close(); // do not forget to close the stream

MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());

0
投票

首先感谢@masmic。 我用它在 github 存储库中进行一些搜索并采用了自己的方式。 请注意,我使用 kotlin、协程和 crashlitics,您可以使用 Java 摆脱所有这些,将线程发布到处理程序并使用 okhttp 将数据发送到您的自定义服务器。

我的代码可以将位图保存到应用程序文件夹,即本地存储。并读取负载:.

package xxxx.data

import android.content.Context
import android.content.ContextWrapper
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.util.Date

interface BitmapDAO {
    suspend fun insertBitmapAndGetRelativePath(bitmapEntity: PhotoEntity): String?

    suspend fun getBitmapFromPath(bitmapEntity: PhotoEntity): Bitmap?

    suspend fun deleteFile(bitmapEntity: PhotoEntity) : Boolean

    suspend fun updateBitmap(bitmapEntity: PhotoEntity): Boolean
}


class BitmapDAOImpl(private val mContext: Context): BitmapDAO {

    companion object{
        //private const val MIME_TYPE_IMAGE:String = "image/*"
        private const val FILE_EXTENSION:String = ".jpeg"
        private const val FOLDER:String = "images"
    }
    private fun convertFromBitMapToByteArray(bitmap: Bitmap) : ByteArray {
        val byteArrayOutputStream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG,100,byteArrayOutputStream)
        return byteArrayOutputStream.toByteArray()
    }
    override suspend fun insertBitmapAndGetRelativePath(bitmapEntity: PhotoEntity): String? {

        val bitmap: Bitmap = bitmapEntity.bitmap.let { bitmap ->
            return@let bitmap
        }?: return null

        val productName: String = bitmapEntity.productName.let {
                productName -> return@let productName
        }?: return null

        // Get the context wrapper
        val wrapper = ContextWrapper(mContext)
        val fileName: String = productName + Date().time.toString() +  FILE_EXTENSION
        try {
            /**
             * Caution: On devices that run Android 7.0 (API level 24) or higher,
             * unless you pass the Context.MODE_PRIVATE file mode
             * into openFileOutput(), a SecurityException occurs.
             */
            return withContext(Dispatchers.IO) {
                // Initialize a new file instance to save bitmap object
                var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE)
                if (!fileDir.exists()) {
                    fileDir.mkdir()
                }
                fileDir = File(fileDir, fileName)
                //with mContext.openFileOutput It gets: EISDIR (Is a directory)
                FileOutputStream(fileDir).use {
                    it.write(convertFromBitMapToByteArray(bitmap))
                }

                //Uri.parse(file.absolutePath)
                return@withContext fileName
            }
        } catch (ex: FileNotFoundException) {
            //REPORT
            Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl")
            Firebase.crashlytics.setCustomKey("Method", "insertBitmapAndGetUri")
            Firebase.crashlytics.setCustomKey("UseCase", "saveImage")
            Firebase.crashlytics.recordException(ex)
            Log.e("BitmapDAOImpl FileNotFoundException", ex.message ?: "")
            Log.e("BitmapDAOImpl FileNotFoundException", ex.stackTrace.toString())
        } catch (ex: IOException) {
            //REPORT
            Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl")
            Firebase.crashlytics.setCustomKey("Method", "insertBitmapAndGetUri")
            Firebase.crashlytics.setCustomKey("UseCase", "saveImage")
            Firebase.crashlytics.recordException(ex)
            Log.e("BitmapDAOImpl IOException", ex.message ?: "")
            Log.e("BitmapDAOImpl IOException", ex.stackTrace.toString())
        }
        //only for Exception case
        return null
    }

    override suspend fun getBitmapFromPath(bitmapEntity: PhotoEntity): Bitmap? {
        try {
            val wrapper = ContextWrapper(mContext)
            return withContext(Dispatchers.IO) {
                var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE)
                if (!fileDir.exists()) {
                    fileDir.mkdir()
                }
                fileDir = File(fileDir, bitmapEntity.fileName)
                var payload : Bitmap? = null
                if (fileDir.exists()){
                    FileInputStream(fileDir).use { fileInputStream ->
                        /**
                         * Loading image
                         */
                        payload = BitmapFactory.decodeStream(fileInputStream)
                    }
                }
                return@withContext payload
            }
        } catch (ex: FileNotFoundException) {
            //REPORT
            Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl")
            Firebase.crashlytics.setCustomKey("Method", "getBitmapFromUri")
            Firebase.crashlytics.setCustomKey("UseCase", "readImage")
            Firebase.crashlytics.recordException(ex)
            Log.e("BitmapDAOImpl", ex.message ?: "")
            Log.e("BitmapDAOImpl", ex.stackTrace.toString())
        } catch (out: OutOfMemoryError) {
            //REPORT
            Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl")
            Firebase.crashlytics.setCustomKey("Method", "getBitmapFromUri")
            Firebase.crashlytics.setCustomKey("UseCase", "readImage")
            Firebase.crashlytics.recordException(out)
            Log.e("BitmapDAOImpl", out.message ?: "")
            Log.e("BitmapDAOImpl", out.stackTrace.toString())
        }

        // If an error has occurred or the album ID is null, then return a default artwork image
        //return BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_launcher_foreground)
        //only for Exception case
        return null
    }

    override suspend fun deleteFile(bitmapEntity: PhotoEntity) : Boolean {
        val wrapper = ContextWrapper(mContext)
        try {
            return withContext(Dispatchers.IO) {
                var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE)
                if (!fileDir.exists()) {
                    fileDir.mkdir()
                }
                fileDir = File(fileDir, bitmapEntity.fileName)
                if(fileDir.exists()){
                    return@withContext fileDir.delete()
                } else {
                    return@withContext false
                }
            }
        } catch (ex: FileNotFoundException) {
            //REPORT
            Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl")
            Firebase.crashlytics.setCustomKey("Method", "deleteFile")
            Firebase.crashlytics.setCustomKey("UseCase", "deleteImage")
            Firebase.crashlytics.recordException(ex)
            Log.e("BitmapDAOImpl", ex.message ?: "")
            Log.e("BitmapDAOImpl", ex.stackTrace.toString())
        }

        //only for Exception case
        return false
    }

    override suspend fun updateBitmap(bitmapEntity: PhotoEntity):Boolean {
        val newImage: Bitmap = bitmapEntity.bitmap.let { newImage ->
            return@let newImage
        }?: return false

        val wrapper = ContextWrapper(mContext)

        try {
            return withContext(Dispatchers.IO) {
                var fileDir = wrapper.getDir(FOLDER, Context.MODE_PRIVATE)
                if (!fileDir.exists()) {
                    fileDir.mkdir()
                }
                fileDir = File(fileDir, bitmapEntity.fileName)
                //if(fileDir.exists()) ?? for both case is the same
                FileOutputStream(fileDir).use {
                    it.write(convertFromBitMapToByteArray(newImage))
                }
                return@withContext true
            }
        } catch (ex: Exception) {
            //REPORT
            Firebase.crashlytics.setCustomKey("Class", "BitmapDAOImpl")
            Firebase.crashlytics.setCustomKey("Method", "updateBitmapAndGetUri")
            Firebase.crashlytics.setCustomKey("UseCase", "updateImage")
            Firebase.crashlytics.recordException(ex)
            Log.e("BitmapDAOImpl", ex.message ?: "")
            Log.e("BitmapDAOImpl", ex.stackTrace.toString())
        }
        return false
    }

} //End of class

谢谢。 祝你有美好的一天。

© www.soinside.com 2019 - 2024. All rights reserved.