Запись файла во внешнее хранилище в Android


Я хочу создать файл во внешнем хранилище sdCard и записать его.Я искал через интернет и пытаюсь,но не получаю результат,я добавил разрешение в файл манифеста Android,а также, я делаю это на эмуляторе, я пытаюсь следующий код и получаю ERRR", "не удалось создать файл".

btnWriteSDFile = (Button) findViewById(R.id.btnWriteSDFile);
btnWriteSDFile.setOnClickListener(new OnClickListener() {
    //private Throwable e;

    @Override
    public void onClick(View v) {
        // write on SD card file data from the text box
        try {
            File myFile = new File("/sdcard/mysdfile.txt");
            myFile.createNewFile();
            FileOutputStream fOut = new FileOutputStream(myFile);
            OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
            myOutWriter.append(txtData.getText());
            myOutWriter.close();
            fOut.close();

        } catch (Exception e) {
              Log.e("ERRR", "Could not create file",e);
        } 
    }// onClick
}); // btnWriteSDFile
7 54

7 ответов:

вы можете сделать это с помощью этого кода также.

 public class WriteSDCard extends Activity {

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

  /** Called when the activity is first created. */
@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");
}
}

для записи во внешнее хранилище в устройствах Lollipop+ нам нужно:

  1. добавьте в манифест следующее разрешение:

           <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  2. запрос утверждения от пользователя:

           public static final int REQUEST_WRITE_STORAGE = 112; 
    
           private requestPermission(Activity context) {
               boolean hasPermission = (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
               if (!hasPermission) {
                  ActivityCompat.requestPermissions(context,
                     new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                   REQUEST_WRITE_STORAGE);
               } else {
                 // You are allowed to write external storage:
                 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/new_folder";
                 File storageDir = new File(path);
                 if (!storageDir.exists() && !storageDir.mkdirs()) {
                   // This should never happen - log handled exception!
                 }
               }
    
  3. обрабатывать ответ пользователя внутри действия:

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
         switch (requestCode)
         {
          case Preferences.REQUEST_WRITE_STORAGE: {
             if (grantResults.length > 0 && grantResults[0] ==  PackageManager.PERMISSION_GRANTED) {
               Toast.makeText(this, "The app was allowed to write to your storage!", Toast.LENGTH_LONG).show();
               // Reload the activity with permission granted or use the features what required the permission
             } else {
               Toast.makeText(this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
         }
     }
    

следует читать документация по хранению вещей внешне на Android. Существует множество проблем, которые могут существовать с вашим текущим кодом, и я думаю, что просмотр документации может помочь вам сгладить их.

Я знаю, что это немного поздно, но я сделал это таким образом, он создает каталог документов, а затем подкаталог для приложения и сохранил файлы в нем.

    public class loadDataTooDisk extends AsyncTask<String, Integer, String>
{
    String sdCardFileTxt;
    @Override
    protected String doInBackground(String... params)
    {

        //check to see if external storage is avalibel
        checkState();
        if(canW == canR == true)
        {
            //get the path to sdcard 
            File pathToExternalStorage = Environment.getExternalStorageDirectory();
            //to this path add a new directory path and create new App dir (InstroList) in /documents Dir
            File appDirectory = new File(pathToExternalStorage.getAbsolutePath()  + "/documents/InstroList");
            // have the object build the directory structure, if needed.
            appDirectory.mkdirs();
            //test to see if it is a Text file
            if ( myNewFileName.endsWith(".txt") )
            {

                //Create a File for the output file data
                File saveFilePath = new File (appDirectory, myNewFileName);
                //Adds the textbox data to the file
                try{
                    String newline = "\r\n";
                    FileOutputStream fos = new FileOutputStream (saveFilePath);
                    OutputStreamWriter OutDataWriter  = new OutputStreamWriter(fos);

                    OutDataWriter.write(equipNo.getText() + newline);
                    // OutDataWriter.append(equipNo.getText() + newline);
                    OutDataWriter.append(equip_Type.getText() + newline);
                    OutDataWriter.append(equip_Make.getText()+ newline);
                    OutDataWriter.append(equipModel_No.getText()+ newline);
                    OutDataWriter.append(equip_Password.getText()+ newline);
                    OutDataWriter.append(equipWeb_Site.getText()+ newline);
                    //OutDataWriter.append(equipNotes.getText());
                    OutDataWriter.close();

                    fos.flush();
                    fos.close();

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

Это один создает имя файла

   private String BuildNewFileName()
    { // creates a new filr name
        Time today = new Time(Time.getCurrentTimezone());
        today.setToNow();

        StringBuilder sb = new StringBuilder();

        sb.append(today.year + "");                // Year)
        sb.append("_");
        sb.append(today.monthDay + "");          // Day of the month (1-31)
        sb.append("_");
        sb.append(today.month + "");              // Month (0-11))
        sb.append("_");
        sb.append(today.format("%k:%M:%S"));      // Current time
        sb.append(".txt");                      //Completed file name

        myNewFileName = sb.toString();
        //Replace (:) with (_)
        myNewFileName = myNewFileName.replaceAll(":", "_");

        return myNewFileName;
    }

хоп это помогает кто-то взял меня много времени, чтобы разобраться и заставить его работать.

 ContextWrapper contextWrapper = new ContextWrapper(getApplicationContext()); //getappcontext for just this activity context get
 File file = contextWrapper.getDir(file_path, Context.MODE_PRIVATE);  
 if (!isExternalStorageAvailable() || isExternalStorageReadOnly()) 
 { 
  saveToExternalStorage.setEnabled(false);
 }
 else
 {
  External_File = new File(getExternalFilesDir(file_path), file_name);//if ready then create a file for external 
 }

}
 try
  {
   FileInputStream fis = new FileInputStream(External_File);
   DataInputStream in = new DataInputStream(fis);
   BufferedReader br =new BufferedReader(new InputStreamReader(in));
   String strLine;
   while ((strLine = br.readLine()) != null) 
   {
    myData = myData + strLine;
   }
   in.close();
  }
  catch (IOException e) 
  {
   e.printStackTrace();
  }
  InputText.setText("Save data of External file::::  "+myData);


private static boolean isExternalStorageReadOnly() 
{ 
 String extStorageState = Environment.getExternalStorageState(); 
 if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState))
 { 
  return true; 
 } 
 return false; 
} 

private static boolean isExternalStorageAvailable()
{ 
 String extStorageState = Environment.getExternalStorageState(); 
 if (Environment.MEDIA_MOUNTED.equals(extStorageState))
 { 
  return true; 
 } 
 return false; 
} 

Дополнительный Ответ

после записи во внешнее хранилище некоторые файловые менеджеры не сразу видят файл. Это может привести к путанице, если пользователь думает, что они скопировали что-то на SD-карту, но затем не могут найти его там. Поэтому после копирования файла запустите следующий код, чтобы уведомить файловые менеджеры о его наличии.

MediaScannerConnection.scanFile(
        context,
        new String[]{myFile.getAbsolutePath()},
        null,
        null);

посмотреть документация и ответ дополнительные.

хотя выше ответы правильные, но я хочу добавить уведомление, чтобы различать типы хранения:

  • внутренний накопитель: Он должен сказать "частное хранилище", потому что он принадлежит приложению и не может быть общим. Место его сохранения зависит от того, где установлено приложение. Если приложение было установлено на SD-карте (я имею в виду внешнюю карту памяти, которую вы помещаете в сотовый телефон для большего пространства для хранения изображений, видео,...), ваш файл будет принадлежать приложению означает ваш файл будет находиться на SD-карте. И если приложение было установлено на внутренней карте (я имею в виду бортовую карту памяти, поставляемую с вашим мобильным телефоном), ваш файл будет находиться на внутренней карте.
  • внешний накопитель: Он должен сказать "общественное хранилище", потому что он может быть общим. И этот режим делится на 2 группы: частное внешнее хранилище и публичное внешнее хранилище. В принципе, они почти одинаковы, вы можете проконсультироваться больше с этого сайта: https://developer.android.com/training/data-storage/files
  • настоящая SD-карта (Я имею в виду внешнюю карту памяти вы положили больше в сотовый телефон для большего пространства для хранения изображений, видео, ...): это не было четко указано в документах Android, поэтому многие люди могут быть смущены тем, как сохранять файлы на этой карте.

вот ссылка на исходный код для случаев, о которых я упоминал выше: https://github.com/mttdat/FileUtils