Archivo de guardado de Android en almacenamiento externo

84

Tengo un pequeño problema al crear un directorio y guardar un archivo en mi aplicación de Android. Estoy usando este código para hacer esto:

String filename = "MyApp/MediaTag/MediaTag-"+objectId+".png";
File file = new File(Environment.getExternalStorageDirectory(), filename);
FileOutputStream fos;

fos = new FileOutputStream(file);
fos.write(mediaTagBuffer);
fos.flush();
fos.close();

Pero está lanzando una excepción:

java.io.FileNotFoundException: /mnt/sdcard/MyApp/MediaCard/MediaCard-0.png (No existe tal archivo o directorio)

en esa línea: fos = new FileOutputStream(file);

Si configuro el nombre del archivo en: "MyApp/MediaTag-"+objectId+" está funcionando, pero si intento crear y guardar el archivo en otro directorio, se produce la excepción. Entonces, ¿alguna idea de lo que estoy haciendo mal?

Y otra pregunta: ¿Hay alguna forma de hacer que mis archivos sean privados en el almacenamiento externo para que el usuario no pueda verlos en la galería, solo si conecta su dispositivo como Disk Drive?

Android-Droid
fuente

Respuestas:

188

Utilice esta función para guardar su mapa de bits en la tarjeta SD

private void SaveImage(Bitmap finalBitmap) {

    String root = Environment.getExternalStorageDirectory().toString();
    File myDir = new File(root + "/saved_images");    
     if (!myDir.exists()) {
                    myDir.mkdirs();
                }
    Random generator = new Random();
    int n = 10000;
    n = generator.nextInt(n);
    String fname = "Image-"+ n +".jpg";
    File file = new File (myDir, fname);
    if (file.exists ())
      file.delete (); 
    try {
        FileOutputStream out = new FileOutputStream(file);
        finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();

    } catch (Exception e) {
         e.printStackTrace();
    }
}

y agrega esto en el manifiesto

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

EDITAR: Al usar esta línea, podrá ver las imágenes guardadas en la vista de galería.

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
                         Uri.parse("file://" + Environment.getExternalStorageDirectory())));

mire este enlace también http://rajareddypolam.wordpress.com/?p=3&preview=true

RajaReddy PolamReddy
fuente
10
Deberías seguir usando en Environment.getExternalStorageDirectory()lugar de /sdcard.
Che Jami
1
solo se guarda en su carpeta, se muestra en la cámara significa que está tomando imágenes a través de la cámara automáticamente y se almacena en la cámara ..
RajaReddy PolamReddy
8
Utilice finallyy no atrape genéricoException
Mr_and_Mrs_D
2
Todo lo anterior @LiamGeorgeBetsworth comportamientos descritos de trabajo , ya que es en pre KitKat .
Muhammad Babar
3
No es apropiado para usar Intent.ACTION_MEDIA_MOUNTEDy no funcionará en KitKat. La intención correcta de transmitir esnew Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file) )
Anthony García-Labiad
28

El código presentado por RajaReddy ya no funciona para KitKat

Este hace (2 cambios):

private void saveImageToExternalStorage(Bitmap finalBitmap) {
    String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
    File myDir = new File(root + "/saved_images");
    myDir.mkdirs();
    Random generator = new Random();
    int n = 10000;
    n = generator.nextInt(n);
    String fname = "Image-" + n + ".jpg";
    File file = new File(myDir, fname);
    if (file.exists())
        file.delete();
    try {
        FileOutputStream out = new FileOutputStream(file);
        finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();
    }
    catch (Exception e) {
        e.printStackTrace();
    }


    // Tell the media scanner about the new file so that it is
    // immediately available to the user.
    MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null,
            new MediaScannerConnection.OnScanCompletedListener() {
                public void onScanCompleted(String path, Uri uri) {
                    Log.i("ExternalStorage", "Scanned " + path + ":");
                    Log.i("ExternalStorage", "-> uri=" + uri);
                }
    });

}
Yar
fuente
2
¿Obtengo uri nulo?
Mukesh
Dígale al escáner de medios sobre el nuevo archivo para que esté inmediatamente disponible para el usuario - me salva el día
Saiful Islam Sajib
7

Actualización 2018, SDK> = 23.

Ahora también debe verificar si el usuario ha otorgado permiso para el almacenamiento externo usando:

public boolean isStoragePermissionGranted() {
    String TAG = "Storage Permission";
    if (Build.VERSION.SDK_INT >= 23) {
        if (this.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG, "Permission is granted");
            return true;
        } else {
            Log.v(TAG, "Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        Log.v(TAG,"Permission is granted");
        return true;
    }
}

public void saveImageBitmap(Bitmap image_bitmap, String image_name) {
    String root = Environment.getExternalStorageDirectory().toString();
    if (isStoragePermissionGranted()) { // check or ask permission
        File myDir = new File(root, "/saved_images");
        if (!myDir.exists()) {
            myDir.mkdirs();
        }
        String fname = "Image-" + image_name + ".jpg";
        File file = new File(myDir, fname);
        if (file.exists()) {
            file.delete();
        }
        try {
            file.createNewFile(); // if file already exists will do nothing
            FileOutputStream out = new FileOutputStream(file);
            image_bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
            out.flush();
            out.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

        MediaScannerConnection.scanFile(this, new String[]{file.toString()}, new String[]{file.getName()}, null);
    }
}

y, por supuesto, agregue el AndroidManifest.xml:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
João Cartucho
fuente
5

Necesitas un permiso para esto

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

y método:

public boolean saveImageOnExternalData(String filePath, byte[] fileData) {

    boolean isFileSaved = false;
    try {
        File f = new File(filePath);
        if (f.exists())
            f.delete();
        f.createNewFile();
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(fileData);
        fos.flush();
        fos.close();
        isFileSaved = true;
        // File Saved
    } catch (FileNotFoundException e) {
        System.out.println("FileNotFoundException");
        e.printStackTrace();
    } catch (IOException e) {
        System.out.println("IOException");
        e.printStackTrace();
    }
    return isFileSaved;
    // File Not Saved
}
Dev Sabby
fuente
4

Prueba esto :

  1. Compruebe el dispositivo de almacenamiento externo
  2. Escribir archivo
  3. Leer archivo
public class WriteSDCard extends Activity {

    private static final String TAG = "MEDIA";
    private TextView tv;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tv = (TextView) findViewById(R.id.TextView01);
        checkExternalMedia();
        writeToSDFile();
        readRaw();
    }

    /**
     * Method to check whether external media available and writable. This is
     * adapted from
     * http://developer.android.com/guide/topics/data/data-storage.html
     * #filesExternal
     */
    private void checkExternalMedia() {
        boolean mExternalStorageAvailable = false;
        boolean mExternalStorageWriteable = false;
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            // Can read and write the media
            mExternalStorageAvailable = mExternalStorageWriteable = true;
        } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            // Can only read the media
            mExternalStorageAvailable = true;
            mExternalStorageWriteable = false;
        } else {
            // Can't read or write
            mExternalStorageAvailable = mExternalStorageWriteable = false;
        }
        tv.append("\n\nExternal Media: readable=" + mExternalStorageAvailable
            + " writable=" + mExternalStorageWriteable);
    }

    /**
     * Method to write ascii text characters to file on SD card. Note that you
     * must add a WRITE_EXTERNAL_STORAGE permission to the manifest file or this
     * method will throw a FileNotFound Exception because you won't have write
     * permission.
     */
    private void writeToSDFile() {
        // Find the root of the external storage.
        // See http://developer.android.com/guide/topics/data/data-
        // storage.html#filesExternal
        File root = android.os.Environment.getExternalStorageDirectory();
        tv.append("\nExternal file system root: " + root);
        // See
        // http://stackoverflow.com/questions/3551821/android-write-to-sd-card-folder
        File dir = new File(root.getAbsolutePath() + "/download");
        dir.mkdirs();
        File file = new File(dir, "myData.txt");
        try {
            FileOutputStream f = new FileOutputStream(file);
            PrintWriter pw = new PrintWriter(f);
            pw.println("Hi , How are you");
            pw.println("Hello");
            pw.flush();
            pw.close();
            f.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.i(TAG, "******* File not found. Did you"
                + " add a WRITE_EXTERNAL_STORAGE permission to the   manifest?");
        } catch (IOException e) {
            e.printStackTrace();
        }
        tv.append("\n\nFile written to " + file);
    }

    /**
     * Method to read in a text file placed in the res/raw directory of the
     * application. The method reads in all lines of the file sequentially.
     */
    private void readRaw() {
        tv.append("\nData read from res/raw/textfile.txt:");
        InputStream is = this.getResources().openRawResource(R.raw.textfile);
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr, 8192); // 2nd arg is buffer
        // size
        // More efficient (less readable) implementation of above is the
        // composite expression
        /*
         * BufferedReader br = new BufferedReader(new InputStreamReader(
         * this.getResources().openRawResource(R.raw.textfile)), 8192);
         */
        try {
            String test;
            while (true) {
                test = br.readLine();
                // readLine() returns null if no more lines in the file
                if (test == null) break;
                tv.append("\n" + "    " + test);
            }
            isr.close();
            is.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        tv.append("\n\nThat is all");
    }
}
Nirav Ranpara
fuente
2
Esto se parece mucho al código de aquí: stackoverflow.com/a/8330635/19679 . Si se extrajo de allí, probablemente debería citarlo en su respuesta.
Brad Larson
4

He creado una AsyncTask para guardar mapas de bits.

public class BitmapSaver extends AsyncTask<Void, Void, Void>
{
    public static final String TAG ="BitmapSaver";

    private Bitmap bmp;

    private Context ctx;

    private File pictureFile;

    public BitmapSaver(Context paramContext , Bitmap paramBitmap)
    {
        ctx = paramContext;

        bmp = paramBitmap;
    }

    /** Create a File for saving an image or video */
    private  File getOutputMediaFile()
    {
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this. 
        File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
                + "/Android/data/"
                + ctx.getPackageName()
                + "/Files"); 

        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                return null;
            }
        } 
        // Create a media file name
        String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
        File mediaFile;
            String mImageName="MI_"+ timeStamp +".jpg";
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);  
        return mediaFile;

    } 
    protected Void doInBackground(Void... paramVarArgs)
    {   
        this.pictureFile = getOutputMediaFile();

        if (this.pictureFile == null) { return null; }

        try
        {
            FileOutputStream localFileOutputStream = new FileOutputStream(this.pictureFile);
            this.bmp.compress(Bitmap.CompressFormat.PNG, 90, localFileOutputStream);
            localFileOutputStream.close();
        }
        catch (FileNotFoundException localFileNotFoundException)
        {
            return null;
        }
        catch (IOException localIOException)
        {
        }
        return null;
    }

    protected void onPostExecute(Void paramVoid)
    {
        super.onPostExecute(paramVoid);

        try
        {
            //it will help you broadcast and view the saved bitmap in Gallery
            this.ctx.sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri
                    .parse("file://" + Environment.getExternalStorageDirectory())));

            Toast.makeText(this.ctx, "File saved", 0).show();

            return;
        }
        catch (Exception localException1)
        {
            try
            {
                Context localContext = this.ctx;
                String[] arrayOfString = new String[1];
                arrayOfString[0] = this.pictureFile.toString();
                MediaScannerConnection.scanFile(localContext, arrayOfString, null,
                        new MediaScannerConnection.OnScanCompletedListener()
                        {
                            public void onScanCompleted(String paramAnonymousString ,
                                    Uri paramAnonymousUri)
                            {
                            }
                        });
                return;
            }
            catch (Exception localException2)
            {
            }
        }
    }
}
AndroidGeek
fuente
¿Cómo puedo guardar una imagen gif?
Vishal Senjaliya
1
La imagen GIF contiene varias imágenes. primero debe separar esos marcos y luego puede usar este método. Es mi opinión.
AndroidGeek
1
Lo hice desde stackoverflow.com/questions/39826400/…
Vishal Senjaliya
3

Probablemente se lanza una excepción porque no hay MediaCardsubdirectorio. Debe verificar si existen todos los directorios en la ruta.

Acerca de la visibilidad de sus archivos: si coloca un archivo con el nombre .nomediaen su directorio, le está diciendo a Android que no desea que lo escanee en busca de archivos multimedia y que no aparecerán en la galería.

Ognyan
fuente
2

desde que se ha cambiado el guardado de archivos de Android 4.4. Ahi esta

ContextCompat.getExternalFilesDirs(context, name);

devuelve una matriz.

cuando el nombre es nulo

el primer valor es como /storage/emulated/0/Android/com.my.package/files

el segundo valor es como /storage/extSdCard/Android/com.my.package/files

Android 4.3 y menos devuelve una matriz de un solo elemento

partes de un pequeño código desordenado pero demuestra cómo funciona:

    /** Create a File for saving an image or video 
     * @throws Exception */
    private File getOutputMediaFile(int type) throws Exception{

        // Check that the SDCard is mounted
        File mediaStorageDir;
        if(internalstorage.isChecked())
        {
            mediaStorageDir = new File(getFilesDir().getAbsolutePath() );
        }
        else
        {
            File[] dirs=ContextCompat.getExternalFilesDirs(this, null);
            mediaStorageDir = new File(dirs[dirs.length>1?1:0].getAbsolutePath() );
        }


        // Create the storage directory(MyCameraVideo) if it does not exist
        if (! mediaStorageDir.exists()){

            if (! mediaStorageDir.mkdirs()){

                output.setText("Failed to create directory.");

                Toast.makeText(this, "Failed to create directory.", Toast.LENGTH_LONG).show();

                Log.d("myapp", "Failed to create directory");
                return null;
            }
        }


        // Create a media file name

        // For unique file name appending current timeStamp with file name
        java.util.Date date= new java.util.Date();
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",Locale.ENGLISH)  .format(date.getTime());

        File mediaFile;

        if(type == MEDIA_TYPE_VIDEO) {

            // For unique video file name appending current timeStamp with file name
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + slpid + "_" + pwsid + "_" + timeStamp + ".mp4");

        }
        else if(type == MEDIA_TYPE_AUDIO) {

            // For unique video file name appending current timeStamp with file name
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + slpid + "_" + pwsid + "_" + timeStamp + ".3gp");

        } else {
            return null;
        }

        return mediaFile;
    }



    /** Create a file Uri for saving an image or video 
     * @throws Exception */
    private  Uri getOutputMediaFileUri(int type) throws Exception{

          return Uri.fromFile(getOutputMediaFile(type));
    }

//usage:
        try {
            file=getOutputMediaFileUri(MEDIA_TYPE_AUDIO).getPath();
        } catch (Exception e1) {
            e1.printStackTrace();
            return;
        }
Shimon Doodkin
fuente
1

Este código funciona muy bien y también funciona en KitKat. Apreciamos a @RajaReddy PolamReddy
Agregó algunos pasos más aquí y también Visible en la Galería.

public void SaveOnClick(View v){
File mainfile;
String fpath;


    try {
//i.e  v2:My view to save on own folder     
        v2.setDrawingCacheEnabled(true);
//Your final bitmap according to my code.
        bitmap_tmp = v2.getDrawingCache();

File(getExternalFilesDir(Environment.DIRECTORY_PICTURES)+File.separator+"/MyFolder");

          Random random=new Random();
          int ii=100000;
          ii=random.nextInt(ii);
          String fname="MyPic_"+ ii + ".jpg";
            File direct = new File(Environment.getExternalStorageDirectory() + "/MyFolder");

            if (!direct.exists()) {
                File wallpaperDirectory = new File("/sdcard/MyFolder/");
                wallpaperDirectory.mkdirs();
            }

            mainfile = new File(new File("/sdcard/MyFolder/"), fname);
            if (mainfile.exists()) {
                mainfile.delete();
            }

              FileOutputStream fileOutputStream;
        fileOutputStream = new FileOutputStream(mainfile);

        bitmap_tmp.compress(CompressFormat.JPEG, 100, fileOutputStream);
        Toast.makeText(MyActivity.this.getApplicationContext(), "Saved in Gallery..", Toast.LENGTH_LONG).show();
        fileOutputStream.flush();
        fileOutputStream.close();
        fpath=mainfile.toString();
        galleryAddPic(fpath);
    } catch(FileNotFoundException e){
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

Este es el escáner de medios a visible en la galería.

private void galleryAddPic(String fpath) {
    Intent mediaScanIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
    File f = new File(fpath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}
Crishnan Iyengar
fuente
1

Para el nivel de API 23 (Marshmallow) y posterior, además del permiso de uso en el manifiesto, también se debe implementar el permiso emergente, y el usuario debe otorgarlo mientras usa la aplicación en tiempo de ejecución.

A continuación, hay un ejemplo para guardar hello world!como contenido de myFile.txtarchivo enTest directorio dentro del directorio de imágenes.

En el manifiesto:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Dónde desea crear el archivo:

int permission = ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);

String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};

if (permission != PackageManager.PERMISSION_GRANTED)
{
     ActivityCompat.requestPermissions(MainActivity.this,PERMISSIONS_STORAGE, 1);
}

File myDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Test");

myDir.mkdirs();

try 
{
    String FILENAME = "myFile.txt";
    File file = new File (myDir, FILENAME);
    String string = "hello world!";
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(string.getBytes());
    fos.close();
 }
 catch (IOException e) {
    e.printStackTrace();
 }
Aryan Firouzian
fuente
0

Haga clic aquí para obtener una descripción completa y el código fuente

public void saveImage(Context mContext, Bitmap bitmapImage) {

  File sampleDir = new File(Environment.getExternalStorageDirectory() + "/" + "ApplicationName");

  TextView tvImageLocation = (TextView) findViewById(R.id.tvImageLocation);
  tvImageLocation.setText("Image Store At : " + sampleDir);

  if (!sampleDir.exists()) {
      createpathForImage(mContext, bitmapImage, sampleDir);
  } else {
      createpathForImage(mContext, bitmapImage, sampleDir);
  }
}
Hitesh Tarbundiya
fuente
1
Agregue una descripción aquí
Mathews Sunny