Mam mały problem z utworzeniem katalogu i zapisaniem w nim pliku w mojej aplikacji na Androida. Aby to zrobić, używam tego fragmentu kodu:
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();
Ale rzuca wyjątek:
java.io.FileNotFoundException: /mnt/sdcard/MyApp/MediaCard/MediaCard-0.png (Brak takiego pliku lub katalogu)
w tej linii: fos = new FileOutputStream(file);
Jeśli ustawię nazwę pliku na: "MyApp/MediaTag-"+objectId+"
działa, ale jeśli spróbuję utworzyć i zapisać plik w innym katalogu, zgłasza wyjątek. Więc jakieś pomysły co robię źle?
I kolejne pytanie: czy jest sposób, aby moje pliki były prywatne w pamięci zewnętrznej, aby użytkownik nie mógł ich zobaczyć w galerii, tylko jeśli podłączy swoje urządzenie jako Disk Drive
?
Environment.getExternalStorageDirectory()
zamiast/sdcard
.finally
i nie łapać ogólnychException
Intent.ACTION_MEDIA_MOUNTED
i nie będzie działać na KitKat. Właściwy zamiar emisji tonew Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file) )
Kod przedstawiony przez RajaReddy nie działa już dla KitKata
To robi (2 zmiany):
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); } }); }
źródło
Aktualizacja 2018, SDK> = 23.
Teraz powinieneś również sprawdzić, czy użytkownik przyznał uprawnienia do zewnętrznej pamięci za pomocą:
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); } }
i oczywiście dodaj
AndroidManifest.xml
:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
źródło
Potrzebujesz do tego pozwolenia
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
i metoda:
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 }
źródło
Upewnij się, że Twoja aplikacja ma odpowiednie uprawnienia do zapisu w pamięci zewnętrznej: http://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE
W twoim pliku manifestu powinno to wyglądać mniej więcej tak:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
źródło
Spróbuj tego :
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"); } }
źródło
Utworzyłem AsyncTask do zapisywania 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) { } } } }
źródło
Prawdopodobnie został zgłoszony wyjątek, ponieważ nie ma
MediaCard
podkatalogu. Powinieneś sprawdzić, czy istnieją wszystkie katalogi w ścieżce.O widoczności twoich plików: jeśli umieścisz plik nazwany
.nomedia
w swoim katalogu , mówisz Androidowi, że nie chcesz, aby skanował go w poszukiwaniu plików multimedialnych i nie pojawią się w galerii.źródło
od czasu zmiany zapisywania plików w systemie Android 4.4. jest
ContextCompat.getExternalFilesDirs(context, name);
ponownie dostraja tablicę.
kiedy nazwa jest pusta
pierwsza wartość to /storage/emulated/0/Android/com.my.package/files
druga wartość to /storage/extSdCard/Android/com.my.package/files
Android 4.3 i mniej przywraca pojedynczą tablicę pozycji
części małego niechlujnego kodu, ale pokazuje, jak to działa:
/** 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; }
źródło
Ten kod działa świetnie i działał również na KitKat. Doceń @RajaReddy PolamReddy
Dodano kilka dodatkowych kroków tutaj, a także widoczne w Galerii.
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(); } }
To jest skaner multimediów widoczny w Galerii.
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); }
źródło
W przypadku interfejsu API na poziomie 23 (Marshmallow) i nowszych, oprócz uprawnień do używania w manifeście, należy również zaimplementować uprawnienie do wyskakujących okienek, a użytkownik musi je przyznać podczas korzystania z aplikacji w czasie wykonywania.
Poniżej znajduje się przykład zapisu
hello world!
jako zawartośćmyFile.txt
pliku wTest
katalogu wewnątrz katalogu ze zdjęciami.W manifeście:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Gdzie chcesz utworzyć plik:
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(); }
źródło
Kliknij tutaj, aby uzyskać pełny opis i kod źródłowy
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); } }
źródło