Android lưu tệp vào bộ nhớ ngoài


84

Tôi gặp một chút vấn đề với việc tạo thư mục và lưu tệp vào đó trên ứng dụng Android của mình. Tôi đang sử dụng đoạn mã này để thực hiện việc này:

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

Nhưng nó ném ra một ngoại lệ:

java.io.FileNotFoundException: /mnt/sdcard/MyApp/MediaCard/MediaCard-0.png (Không có tệp hoặc thư mục như vậy)

trên dòng đó: fos = new FileOutputStream(file);

Nếu tôi đặt tên tệp thành: "MyApp/MediaTag-"+objectId+"nó đang hoạt động, nhưng Nếu tôi cố gắng tạo và lưu tệp vào một thư mục khác, nó sẽ đưa ra ngoại lệ. Vì vậy, bất kỳ ý tưởng những gì tôi đang làm sai?

Và một câu hỏi khác: Có cách nào để đặt tệp của tôi ở chế độ riêng tư trong bộ nhớ ngoài để người dùng không thể xem chúng trong thư viện, chỉ khi anh ta kết nối thiết bị của mình với tư cách là Disk Drive?

Câu trả lời:


187

Sử dụng chức năng này để lưu ảnh bitmap của bạn trong thẻ 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();
    }
}

và thêm điều này vào tệp kê khai

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

CHỈNH SỬA: Bằng cách sử dụng dòng này, bạn sẽ có thể xem các hình ảnh đã lưu trong chế độ xem thư viện.

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

cũng nhìn vào liên kết này http://rajareddypolam.wordpress.com/?p=3&preview=true


10
Bạn vẫn nên sử dụng Environment.getExternalStorageDirectory()thay vì /sdcard.
Che Jami 25/10/11

1
nó tiết kiệm trong thư mục của bạn chỉ, nó cho thấy trong máy ảnh có nghĩa là bạn đang dùng hình ảnh thông qua máy ảnh tự động nó trong các cửa hàng máy ảnh ..
RajaReddy PolamReddy

8
Vui lòng sử dụng finallyvà không bắt chung chungException
Mr_and_Mrs_D

2
@LiamGeorgeBetsworth Tất cả trên những hành vi được mô tả công việc vì nó làtrước KitKat .
Muhammad Babar

3
Nó không thích hợp để sử dụng Intent.ACTION_MEDIA_MOUNTEDvà sẽ không hoạt động trên KitKat. Mục đích chính xác để phát sóng lànew Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file) )
Anthony Garcia-Labiad

28

Mã do RajaReddy trình bày không còn hoạt động với KitKat

Cái này thực hiện (2 thay đổi):

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
Tôi nhận được nước tiểu không?
Mukesh

Cho quét phương tiện truyền thông về các tập tin mới để nó có sẵn ngay lập tức cho người sử dụng - nó tiết kiệm ngày của tôi
Saiful Islam Sajib

7

Cập nhật 2018, SDK> = 23.

Bây giờ bạn cũng nên kiểm tra xem người dùng đã cấp quyền cho bộ nhớ ngoài hay chưa bằng cách sử dụng:

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

và tất nhiên, thêm vào AndroidManifest.xml:

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

5

Bạn cần một sự cho phép cho việc này

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

và phương pháp:

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

Thử đi :

  1. Kiểm tra thiết bị lưu trữ bên ngoài
  2. Viết tệp
  3. Đọc tài liệu
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
Điều này trông rất giống với mã từ đây: stackoverflow.com/a/8330635/19679 . Nếu nó được rút ra từ đó, bạn có thể nên trích dẫn điều đó trong câu trả lời của mình.
Brad Larson

4

Tôi đã tạo AsyncTask để lưu ảnh bitmap.

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

Làm cách nào để lưu ảnh gif ??
Vishal Senjaliya

1
Ảnh gif chứa nhiều ảnh. trước tiên bạn phải tách các khung đó ra rồi mới có thể sử dụng phương pháp này. Đó là ý kiến ​​của tôi.
AndroidGeek

1
tôi đã làm điều đó từ stackoverflow.com/questions/39826400/…
Vishal Senjaliya

3

Có lẽ ngoại lệ được ném vì không có phụ MediaCard. Bạn nên kiểm tra xem tất cả các dirs trong đường dẫn có tồn tại hay không.

Về khả năng hiển thị tệp của bạn: nếu bạn đặt tệp có tên .nomediatrong dir của mình, bạn đang nói với Android rằng bạn không muốn nó quét để tìm tệp phương tiện và chúng sẽ không xuất hiện trong thư viện.


2

kể từ khi lưu tệp android 4.4 đã được thay đổi. có

ContextCompat.getExternalFilesDirs(context, name);

nó retuns một mảng.

khi tên rỗng

giá trị đầu tiên giống như /storage/emulated/0/Android/com.my.package/files

giá trị thứ hai giống như /storage/extSdCard/Android/com.my.package/files

android 4.3 trở xuống, nó sửa lại một mảng mục duy nhất

các phần của mã lộn xộn nhưng nó thể hiện cách hoạt động:

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

Mã này hoạt động tốt và hoạt động tốt trên KitKat. Đánh giá cao @RajaReddy PolamReddy
Đã thêm một số bước nữa ở đây và cũng có thể Hiển thị trên Thư viện.

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

}

Đây là máy quét phương tiện để hiển thị trong Bộ sưu tập.

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

1

Đối với API cấp 23 (Marshmallow) trở lên, bổ sung cho quyền sử dụng trong tệp kê khai, quyền bật lên cũng phải được triển khai và người dùng cần cấp quyền đó khi sử dụng ứng dụng trong thời gian chạy.

Dưới đây, có một ví dụ để lưu hello world!dưới dạng nội dung của myFile.txttệp trong Testthư mục bên trong thư mục ảnh.

Trong tệp kê khai:

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

Nơi bạn muốn tạo tệp:

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

Nhấp vào đây để xem mô tả đầy đủ và mã nguồn

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
Thêm một số mô tả ở đây
Mathews Sunny
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.