Implementación de un selector de archivos en Android y copia del archivo seleccionado en otra ubicación

Estoy intentando implementar un selector de archivos en mi proyecto de Android. Lo que he podido hacer hasta ahora es:

Intent chooseFile; Intent intent; chooseFile = new Intent(Intent.ACTION_GET_CONTENT); chooseFile.setType("*/*"); intent = Intent.createChooser(chooseFile, "Choose a file"); startActivityForResult(intent, PICKFILE_RESULT_CODE); 

Y luego en mi onActivityResult()

 switch(requestCode){ case PICKFILE_RESULT_CODE: if(resultCode==-1){ Uri uri = data.getData(); String filePath = uri.getPath(); Toast.makeText(getActivity(), filePath, Toast.LENGTH_LONG).show(); } break; } 

Esto es abrir un selector de archivos, pero no es lo que quiero. Por ejemplo, quiero seleccionar un archivo (.txt), y luego obtener ese File y luego usarlo. Con este código pensé que conseguiría el camino completo pero no sucede; Por ejemplo, obtengo: /document/5318/ . Pero con este camino no puedo conseguir el archivo. He creado un método llamado PathToFile() que devuelve un File :

  private File PathToFile(String path) { File tempFileToUpload; tempFileToUpload = new File(path); return tempFileToUpload; } 

Lo que estoy tratando de hacer es dejar que el usuario elija un File desde cualquier lugar significa DropBox , Drive , SDCard , Mega , etc … Y no encuentro la manera de hacerlo correctamente, Traté de obtener el Path continuación, obtener Un File por esta Path … pero no funciona, por lo que creo que es mejor para obtener el File sí, y luego con este File programación Copy esto o Delete .

EDIT (código actual)

Mi Intent

  Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT); chooseFile.addCategory(Intent.CATEGORY_OPENABLE); chooseFile.setType("text/plain"); startActivityForResult( Intent.createChooser(chooseFile, "Choose a file"), PICKFILE_RESULT_CODE ); 

Allí tengo una pregunta porque no sé qué es compatible con el text/plain , pero voy a investigar sobre él, pero no importa en este momento.

En mi onActivityResult() He utilizado lo mismo que @Lukas Knuth respuesta , pero no sé si con él puedo Copy este File a otra parte de mi SDcard Estoy esperando su respuesta.

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == PICKFILE_RESULT_CODE && resultCode == Activity.RESULT_OK){ Uri content_describer = data.getData(); //get the path Log.d("Path???", content_describer.getPath()); BufferedReader reader = null; try { // open the user-picked file for reading: InputStream in = getActivity().getContentResolver().openInputStream(content_describer); // now read the content: reader = new BufferedReader(new InputStreamReader(in)); String line; StringBuilder builder = new StringBuilder(); while ((line = reader.readLine()) != null){ builder.append(line); } // Do something with the content in text.setText(builder.toString()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 

getPath() de @YS

Estoy haciendo esto :

  String[] projection = { MediaStore.Files.FileColumns.DATA }; Cursor cursor = getActivity().getContentResolver().query(content_describer, projection, null, null, null); int column_index = cursor.getColumnIndexOrThrow(projection[0]); cursor.moveToFirst(); cursor.close(); Log.d( "PATH-->",cursor.getString(column_index)); 

Está recibiendo una NullPointerException :

Java.lang.RuntimeException: Fallo en la entrega del resultado ResultInfo {who = null, request = 131073, result = -1, data = Intent {dat = file: /// path typ = text / plain flg = 0x3}} .androidhive.tabsswipe / info.androidhive.tabsswipe.MainActivity2}: java.lang.NullPointerException

EDIT con código trabajando gracias a @YS , @Lukas Knuth y @CommonsWare .

Esta es la Intent donde sólo acepto archivos de text/plain .

 Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT); chooseFile.addCategory(Intent.CATEGORY_OPENABLE); chooseFile.setType("text/plain"); startActivityForResult( Intent.createChooser(chooseFile, "Choose a file"), PICKFILE_RESULT_CODE ); 

En mi onActivityResult() creo un URI donde obtengo los datos de la Intent , creo un File donde guardo la ruta absoluta haciendo content_describer.getPath(); , Y luego mantener el nombre de la ruta de acceso para utilizarlo en un TextView con content_describer.getLastPathSegment(); (Que era impresionante @YS no sabía acerca de esa función), y creo un segundo File que he llamado destination y envío el AbsolutePath para crear este File .

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == PICKFILE_RESULT_CODE && resultCode == Activity.RESULT_OK){ Uri content_describer = data.getData(); String src = content_describer.getPath(); source = new File(src); Log.d("src is ", source.toString()); String filename = content_describer.getLastPathSegment(); text.setText(filename); Log.d("FileName is ",filename); destination = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Test/TestTest/" + filename); Log.d("Destination is ", destination.toString()); SetToFolder.setEnabled(true); } } 

También he creado una función que usted tiene que enviar el source file , y el destination file que hemos creado previamente para copiar esto a la nueva carpeta.

 private void copy(File source, File destination) throws IOException { FileChannel in = new FileInputStream(source).getChannel(); FileChannel out = new FileOutputStream(destination).getChannel(); try { in.transferTo(0, in.size(), out); } catch(Exception e){ Log.d("Exception", e.toString()); } finally { if (in != null) in.close(); if (out != null) out.close(); } } 

También he creado una función que me dice si esta carpeta existe o no (tengo que enviar el destination file , si no existe creo esta carpeta y si no lo hago no hago nada.

 private void DirectoryExist (File destination) { if(!destination.isDirectory()) { if(destination.mkdirs()){ Log.d("Carpeta creada","...."); }else{ Log.d("Carpeta no creada","...."); } } 

Gracias de nuevo por su ayuda, espero que disfrute de este código hecho con todos ustedes chicos 🙂

PASO 1 – Utilizar una Intent implícita:

Para elegir un archivo desde el dispositivo, debe utilizar un Intent implícito

 Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT); chooseFile.setType("*/*"); chooseFile = Intent.createChooser(chooseFile, "Choose a file"); startActivityForResult(chooseFile, PICKFILE_RESULT_CODE); 

PASO 2 – Obtener la ruta absoluta del archivo:

Para obtener la ruta del archivo desde un Uri , intente primero usar

 Uri uri = data.getData(); String src = uri.getPath(); 

Donde los data son el Intent devuelto en onActivityResult() .

Si eso no funciona, utilice el siguiente método:

 public String getPath(Uri uri) { String path = null; String[] projection = { MediaStore.Files.FileColumns.DATA }; Cursor cursor = getContentResolver().query(uri, projection, null, null, null); if(cursor == null){ path = uri.getPath() } else{ cursor.moveToFirst(); int column_index = cursor.getColumnIndexOrThrow(projection[0]); path = cursor.getString(column_index); cursor.close(); } return ((path == null || path.isEmpty()) ? (uri.getPath()) : path); } 

Al menos uno de estos dos métodos debe obtener el camino correcto y completo.

PASO 3 – Copie el archivo:

Lo que quieres, creo, es copiar un archivo de una ubicación a otra.

Para ello, es absolutamente necesario tener la ruta absoluta del archivo de las ubicaciones de origen y de destino.

Primero, obtenga la ruta absoluta del archivo utilizando mi método uri.getPath() o uri.getPath() :

 String src = getPath(uri); /* Method defined above. */ 

o

 Uri uri = data.getData(); String src = uri.getPath(); 

A continuación, cree dos objetos de File como sigue:

 File source = new File(src); String filename = uri.getLastPathSegment(); File destination = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/CustomFolder/" + filename); 

Donde CustomFolder es el directorio en la unidad externa donde desea copiar el archivo.

A continuación, utilice el siguiente método para copiar un archivo de un lugar a otro:

 private void copy(File source, File destination) { FileChannel in = new FileInputStream(source).getChannel(); FileChannel out = new FileOutputStream(destination).getChannel(); try { in.transferTo(0, in.size(), out); } catch(Exception){ // post to log } finally { if (in != null) in.close(); if (out != null) out.close(); } } 

Prueba esto. Esto debería funcionar.

Nota: Frente a la respuesta de Lukas, lo que ha hecho es usar un método llamado openInputStream() que devuelve el contenido de un Uri , ya sea que Uri represente un archivo o una URL.

Otro enfoque prometedor – el FileProvider :

Hay una manera más por medio de la cual es posible obtener un archivo de otra aplicación. Si una aplicación comparte sus archivos a través de FileProvider , es posible obtener un objeto FileDescriptor que contiene información específica sobre este archivo.

Para ello, utilice el siguiente Intent :

 Intent mRequestFileIntent = new Intent(Intent.ACTION_GET_CONTENT); mRequestFileIntent.setType("*/*"); startActivityForResult(mRequestFileIntent, 0); 

Y en su onActivityResult() :

 @Override public void onActivityResult(int requestCode, int resultCode, Intent returnIntent) { // If the selection didn't work if (resultCode != RESULT_OK) { // Exit without doing anything else return; } else { // Get the file's content URI from the incoming Intent Uri returnUri = returnIntent.getData(); /* * Try to open the file for "read" access using the * returned URI. If the file isn't found, write to the * error log and return. */ try { /* * Get the content resolver instance for this context, and use it * to get a ParcelFileDescriptor for the file. */ mInputPFD = getContentResolver().openFileDescriptor(returnUri, "r"); } catch (FileNotFoundException e) { e.printStackTrace(); Log.e("MainActivity", "File not found."); return; } // Get a regular file descriptor for the file FileDescriptor fd = mInputPFD.getFileDescriptor(); ... } } 

Donde mInputPFD es un ParcelFileDescriptor .

Referencias:

1. Intenciones Comunes – Almacenamiento de Archivos .

2. FileChannel .

3. FileProvider .

4. Solicitud de un archivo compartido .

Hice lo mismo para permitir al usuario elegir una imagen de una carpeta:

1) hay un botón ABIERTO:

 @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_open: myOpenImagePicker(); break; } } 

2) la función de carpeta de imagen abierta:

 @SuppressLint("InlinedApi") public void myOpenImagePicker() { if (Build.VERSION.SDK_INT < 19) { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult( Intent.createChooser(intent, "Select Picture"), SELECT_FOLDER); } else { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("image/*"); startActivityForResult(intent, SELECT_FOLDER); } } 

3) el resultado de la actividad donde consigo la trayectoria del archivo de la imagen y hago lo que quiera con la trayectoria de la imagen:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case SELECT_FOLDER: if (resultCode == RESULT_OK && data != null) { Uri originalUri = data.getData(); String id01 = W_ImgFilePathUtil.getPath( getApplicationContext(), originalUri); Bitmap unscaledBitmap = W_ImgScalingUtil.decodeResource(id01, xdrawing.getViewWidth(), xdrawing.getViewHeight(), ScalingLogic.FIT); if (unscaledBitmap == null) { zprefsutil.ShowToast("IMAGE ERROR", 1); } else { setExternalScaledBitmap(W_ImgScalingUtil .createScaledBitmap(unscaledBitmap, xdrawing.getViewWidth(), xdrawing.getViewHeight(), ScalingLogic.FIT)); unscaledBitmap.recycle(); xdrawing.invalidate(); } } break; default: break; } } 

4) y ahora la parte MÁS IMPORTANTE, la clase W_ImgFilePathUtil, el código no es de mí, sino que le permite recuperar la ruta completa de cualquier archivo seleccionado, ya sea en tarjeta sd, unidad de google, …:

Public class W_ImgFilePathUtil {

 /** * Method for return file path of Gallery image * * @param context * @param uri * @return path of the selected image file from gallery */ @SuppressLint("NewApi") public static String getPath(final Context context, final Uri uri) { // check here to KITKAT or new version final boolean isKitKatorUp = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentProvider if (isKitKatorUp && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } } // DownloadsProvider else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[] { split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { // Return the remote address if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } /** * Get the value of the data column for this Uri. This is useful for * MediaStore Uris, and other file-based ContentProviders. * * @param context * The context. * @param uri * The Uri to query. * @param selection * (Optional) Filter used in the query. * @param selectionArgs * (Optional) Selection arguments used in the query. * @return The value of the _data column, which is typically a file path. */ public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; final String[] projection = { column }; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { final int index = cursor.getColumnIndexOrThrow(column); return cursor.getString(index); } } finally { if (cursor != null) cursor.close(); } return null; } /** * @param uri * The Uri to check. * @return Whether the Uri authority is ExternalStorageProvider. */ public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri .getAuthority()); } /** * @param uri * The Uri to check. * @return Whether the Uri authority is DownloadsProvider. */ public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri .getAuthority()); } /** * @param uri * The Uri to check. * @return Whether the Uri authority is MediaProvider. */ public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri .getAuthority()); } /** * @param uri * The Uri to check. * @return Whether the Uri authority is Google Photos. */ public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri .getAuthority()); } 

}

CONCLUSIÓN: el código trabaja con la trayectoria de la imagen pero trabaja seguro con cualquier clase de archivo.

Espero que esto ayude a resolver su problema.

PAZ.

Un Uri no es un archivo . Un Uri está más cerca de una URL de servidor web. Es una dirección opaca, que sólo tiene significado para el "servidor" (o en este caso, el ContentProvider ).

Así como se utiliza un InputStream para leer en los bytes representados por una URL Web, se utiliza un InputStream para leer en los bytes representados por el Uri . Obtendrá un flujo de este tipo llamando a openInputStream() en un ContentResolver .

Como ya se ha mencionado en @CommonsWare , Android te devuelve un Uri , que es un concepto más abstracto que una ruta de archivo.

También puede describir una ruta de archivo sencilla, pero también puede describir un recurso al que se accede a través de una aplicación (como content://media/external/audio/media/710 ).

Si desea que su usuario escriba cualquier archivo del teléfono para leerlo desde su aplicación, puede hacerlo pidiendo el archivo (como lo hizo correctamente) y luego use ContentResolver para obtener un InputStream para el Uri que es devuelto por El recogedor.

Aquí hay un ejemplo:

 Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT); // Ask specifically for something that can be opened: chooseFile.addCategory(Intent.CATEGORY_OPENABLE); chooseFile.setType("*/*"); startActivityForResult( Intent.createChooser(chooseFile, "Choose a file"), PICKFILE_REQUEST_CODE ); // And then somewhere, in your activity: @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == PICKFILE_REQUEST_CODE && resultCode == RESULT_OK){ Uri content_describer = data.getData(); BufferedReader reader = null; try { // open the user-picked file for reading: InputStream in = getContentResolver().openInputStream(content_describer); // now read the content: reader = new BufferedReader(new InputStreamReader(in)); String line; StringBuilder builder = new StringBuilder(); while ((line = reader.readLine()) != null){ builder.append(line); } // Do something with the content in some_view.setText(builder.toString()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } } 

Importante : Algunos proveedores (como Dropbox) almacenan / almacenan en caché sus datos en el almacenamiento externo. Tendrá que tener el android.permission.READ_EXTERNAL_STORAGE -permission declarado en su manifiesto, de lo contrario obtendrá FileNotFoundException , aunque el archivo esté allí.


Actualización : sí, puede copiar el archivo leyéndolo desde una secuencia y escribiéndolo a otro:

 // Error handling is omitted for shorter code! Uri content_describer = data.getData(); InputStream in = null; OutputStream out = null; try { // open the user-picked file for reading: in = getContentResolver().openInputStream(content_describer); // open the output-file: out = new FileOutputStream(new File("some/path/to/a/writable/file")); // copy the content: byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } // Contents are copied! } finally { if (in != null) { in.close(); } if (out != null){ out.close(); } } 

La eliminación del archivo probablemente no sea posible, ya que el archivo no le pertenece , pertenece a la aplicación que lo compartió con el suyo. Por lo tanto, la aplicación propietario es responsable de eliminar el archivo.

Pase el URI devuelto en onActivityResult en este método

 private String getPath(Uri contentURI) { String result; Cursor cursor = getActivity().getContentResolver().query(contentURI, null, null, null, null); if (cursor == null) { result = contentURI.getPath(); } else { cursor.moveToFirst(); int idx = cursor .getColumnIndex(MediaStore.Images.ImageColumns.DATA); result = cursor.getString(idx); cursor.close(); } return result; } 
  • Botón de Android onClickListener
  • Cómo configurar el color de fondo para Textview de forma programática para otro archivo xml?
  • Android dibuja una línea horizontal entre vistas
  • ¿Cuál es la diferencia entre declarar un filtro intencional en una actividad frente a un receptor?
  • Iniciar IntentService de Actividad y actualizar Actividad cuando IntentService finaliza
  • Prueba "real" del receptor de sms
  • Se muestra una página en blanco cuando se abre el fragmento y se vuelve a colocar en el mismo fragmento
  • Abrir la aplicación de Facebook en la página de perfil especificada
  • Insertar androide en pila de actividad
  • Android: el video se puede reproducir desde la galería pero cuando lo reproduzco usando el video de tipo Intent.ACTION_VIEW, no se puede reproducir
  • Obtener contactos actualizados en Android para sincronización de contactos
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.