Android บันทึกไฟล์ไปยังที่จัดเก็บข้อมูลภายนอก


84

ฉันมีปัญหาเล็กน้อยกับการสร้างไดเร็กทอรีและบันทึกไฟล์ลงในแอปพลิเคชัน Android ของฉัน ฉันใช้โค้ดชิ้นนี้เพื่อทำสิ่งนี้:

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

แต่มันมีข้อยกเว้น:

java.io.FileNotFoundException: /mnt/sdcard/MyApp/MediaCard/MediaCard-0.png (ไม่มีไฟล์หรือไดเร็กทอรีดังกล่าว)

ในบรรทัดนั้น: fos = new FileOutputStream(file);

ถ้าฉันตั้งชื่อไฟล์เป็น: "MyApp/MediaTag-"+objectId+"มันใช้งานได้ แต่ถ้าฉันพยายามสร้างและบันทึกไฟล์ไปยังไดเร็กทอรีอื่นมันจะทำให้เกิดข้อยกเว้น มีความคิดอะไรที่ฉันทำผิด?

และอีกคำถาม: มีวิธีใดบ้างที่จะทำให้ไฟล์ของฉันเป็นส่วนตัวในที่จัดเก็บข้อมูลภายนอกเพื่อให้ผู้ใช้ไม่สามารถเห็นไฟล์เหล่านี้ในแกลเลอรีได้เฉพาะเมื่อเขาเชื่อมต่ออุปกรณ์ของเขาเป็นDisk Drive?

คำตอบ:


188

ใช้ฟังก์ชันนี้เพื่อบันทึกบิตแมปของคุณในการ์ด 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();
    }
}

และเพิ่มสิ่งนี้ในไฟล์ Manifest

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

แก้ไข:เมื่อใช้บรรทัดนี้คุณจะสามารถดูภาพที่บันทึกไว้ในมุมมองแกลเลอรี

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

ดูลิงค์นี้ด้วยhttp://rajareddypolam.wordpress.com/?p=3&preview=true


10
คุณยังควรใช้Environment.getExternalStorageDirectory()แทน/sdcard.
Che Jami

1
จะบันทึกในโฟลเดอร์ของคุณเท่านั้นโดยจะแสดงในกล้องหมายความว่าคุณกำลังถ่ายภาพผ่านกล้องโดยอัตโนมัติซึ่งจะจัดเก็บไว้ในกล้องถ่ายรูป ..
RajaReddy PolamReddy

8
โปรดใช้finallyและอย่าจับทั่วไปException
Mr_and_Mrs_D

2
@LiamGeorgeBetsworth ทั้งหมดข้างต้นอธิบายพฤติกรรมการทำงานที่มันเป็นในก่อน KitKat
มูฮัมหมัดบาบาร์

3
ไม่เหมาะสมที่จะใช้Intent.ACTION_MEDIA_MOUNTEDและจะไม่ทำงานกับ KitKat เจตนาที่ถูกต้องในการออกอากาศคือnew Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file) )
Anthony Garcia-Labiad

28

รหัสที่ RajaReddy นำเสนอใช้ไม่ได้กับ KitKat อีกต่อไป

สิ่งนี้ทำ (2 การเปลี่ยนแปลง):

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

}

2
ฉันได้รับ uri null?
Mukesh

แจ้งเครื่องสแกนสื่อเกี่ยวกับไฟล์ใหม่เพื่อให้ผู้ใช้สามารถใช้งานได้ทันที - บันทึกวันของฉัน
Saiful Islam Sajib

8

อัปเดต 2018, SDK> = 23

ตอนนี้คุณควรตรวจสอบด้วยว่าผู้ใช้ให้สิทธิ์ที่เก็บข้อมูลภายนอกหรือไม่โดยใช้:

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

และแน่นอนเพิ่มในAndroidManifest.xml:

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

5

คุณต้องได้รับอนุญาตสำหรับสิ่งนี้

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

และวิธีการ:

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
}

4

ตรวจสอบให้แน่ใจว่าแอปของคุณมีสิทธิ์ที่เหมาะสมที่จะได้รับอนุญาตให้เขียนไปยังที่จัดเก็บข้อมูลภายนอก: http://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE

ควรมีลักษณะดังนี้ในไฟล์ Manifest ของคุณ:

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

4

ลองสิ่งนี้:

  1. ตรวจสอบอุปกรณ์จัดเก็บข้อมูลภายนอก
  2. เขียนไฟล์
  3. อ่านไฟล์
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");
    }
}

2
นี้มีลักษณะคล้ายกับรหัสจากที่นี่: stackoverflow.com/a/8330635/19679 ถ้ามันถูกดึงออกมาจากที่นั่นคุณควรจะอ้างถึงสิ่งนั้นในคำตอบของคุณ
Brad Larson

4

ฉันได้สร้าง AsyncTask สำหรับบันทึกบิตแมป

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

ฉันจะบันทึกภาพ gif ได้อย่างไร?
Vishal Senjaliya

1
ภาพ Gif มีหลายภาพ คุณต้องแยกเฟรมเหล่านั้นก่อนจากนั้นคุณสามารถใช้วิธีนี้ได้ มันเป็นความคิดเห็นของฉัน
AndroidGeek


3

อาจมีข้อยกเว้นเกิดขึ้นเนื่องจากไม่มีMediaCardsubdir คุณควรตรวจสอบว่ามี dirs ทั้งหมดในเส้นทางหรือไม่

เกี่ยวกับการมองเห็นไฟล์ของคุณ: หากคุณใส่ชื่อไฟล์ไว้.nomediaใน dir คุณกำลังบอก Android ว่าคุณไม่ต้องการให้สแกนหาไฟล์มีเดียและไฟล์เหล่านั้นจะไม่ปรากฏในแกลเลอรี


2

เนื่องจากมีการเปลี่ยนแปลงการบันทึกไฟล์ android 4.4 มี

ContextCompat.getExternalFilesDirs(context, name);

มันเรียกใช้อาร์เรย์ใหม่

เมื่อชื่อเป็นโมฆะ

ค่าแรกเป็นเช่น /storage/emulated/0/Android/com.my.package/files

ค่าที่สองเป็นเช่น /storage/extSdCard/Android/com.my.package/files

android 4.3 และน้อยกว่ามันจะเรียกใช้อาร์เรย์รายการเดียว

บางส่วนของโค้ดที่ยุ่งเล็กน้อย แต่แสดงให้เห็นถึงวิธีการทำงาน:

    /** 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;
        }

1

สำหรับ API ระดับ 23 (Marshmallow) และใหม่กว่าควรใช้สิทธิ์การใช้งานเพิ่มเติมในไฟล์ Manifest การอนุญาตป๊อปอัปและผู้ใช้ต้องให้สิทธิ์ขณะใช้แอปในรันไทม์

ด้านล่างนี้มีตัวอย่างการบันทึกhello world!เป็นเนื้อหาของmyFile.txtไฟล์ในTestไดเร็กทอรีภายในไดเร็กทอรีรูปภาพ

ในรายการ:

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

ตำแหน่งที่คุณต้องการสร้างไฟล์:

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

0

รหัสนี้ใช้งานได้ดีและทำงานกับ KitKat ได้เป็นอย่างดี ชื่นชม @RajaReddy PolamReddy
เพิ่มอีกไม่กี่ขั้นตอนที่นี่และยังมองเห็นได้ในแกลเลอรีด้วย

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

}

นี่คือเครื่องสแกนสื่อที่มองเห็นได้ในคลังภาพ

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

0

คลิกที่นี่เพื่อดูรายละเอียดทั้งหมดและซอร์สโค้ด

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

1
เพิ่มคำอธิบายที่นี่
Mathews Sunny
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.