J'essaie d'implémenter un sélecteur de fichiers dans mon projet Android. Ce que j'ai pu faire jusqu'à présent, c'est:
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);
Et puis dans ma 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;
}
Cela ouvre un sélecteur de fichiers, mais ce n'est pas ce que je veux. Par exemple, je souhaite sélectionner un fichier (.txt), puis obtenir ce File
, puis l'utiliser. Avec ce code, j'ai pensé que j'obtiendrais le chemin complet mais cela ne se produit pas; par exemple, j'obtiens: /document/5318/
. Mais avec ce chemin, je ne peux pas obtenir le fichier. J'ai créé une méthode appelée PathToFile()
qui renvoie un File
:
private File PathToFile(String path) {
File tempFileToUpload;
tempFileToUpload = new File(path);
return tempFileToUpload;
}
Ce que j'essaie de faire est de laisser l'utilisateur choisir un File
de n'importe où signifie DropBox
, Drive
, SDCard
, Mega
, etc ... Et je ne trouve pas le moyen de le faire correctement, j'ai essayé d'obtenir le Path
puis un File
par ce Path
... mais ça ne fonctionne pas, donc je pense qu'il vaut mieux obtenir le File
lui-même, puis avec ce File
par programme je Copy
ceci ou Delete
.
Mon 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
);
Là, j'ai une question parce que je ne sais pas ce qui est supporté comme text/plain
, Mais je vais enquêter à ce sujet, mais cela n'a pas d'importance pour le moment.
Sur ma onActivityResult()
j'ai utilisé la même chose que @ réponse Lukas Knuth , mais je ne sais pas si avec elle je peux Copy
cette File
à une autre partie de mon SDcard
j'attends sa réponse.
@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 @ Y.S.
Je fais ça :
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));
Obtient un NullPointerException
:
Java.lang.RuntimeException: échec de la livraison du résultat ResultInfo {who = null, request = 131073, result = -1, data = Intent {dat = file: /// path typ = text/plain flg = 0x3}} to activity {info .androidhive.tabsswipe/info.androidhive.tabsswipe.MainActivity2}: Java.lang.NullPointerException
C'est le Intent
où j'accepte uniquement les fichiers 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
);
Sur ma onActivityResult()
je crée un URI
où j'obtiens les données du Intent
, je crée un File
où je sauvegarde le chemin absolu faisant content_describer.getPath();
, puis je garde le nom du chemin pour l'utiliser dans un TextView
avec content_describer.getLastPathSegment();
(c'était génial @YS ne connaissait pas cette fonction), et je crée un second File
que j'ai appelé destination
et j'envoie le AbsolutePath
pour pouvoir créer ce 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);
}
}
J'ai également créé une fonction que vous devez envoyer le source file
, Et destination file
Que nous avons créé précédemment pour le copier dans le nouveau dossier.
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();
}
}
J'ai aussi créé une fonction qui me dit si ce dossier existe ou non (je dois envoyer le destination file
, S'il n'existe pas je crée ce dossier et si ce n'est pas je ne fais rien .
private void DirectoryExist (File destination) {
if(!destination.isDirectory()) {
if(destination.mkdirs()){
Log.d("Carpeta creada","....");
}else{
Log.d("Carpeta no creada","....");
}
}
Merci encore pour votre aide, j'espère que vous apprécierez ce code créé avec tout le monde :)
ÉTAPE 1 - Utilisez un _ implicite Intent
:
Pour choisir un fichier sur le périphérique, vous devez utiliser un Intent
implicite _
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("*/*");
chooseFile = Intent.createChooser(chooseFile, "Choose a file");
startActivityForResult(chooseFile, PICKFILE_RESULT_CODE);
ÉTAPE 2 - Obtenez le chemin absolu du fichier:
Pour obtenir le chemin du fichier à partir d'un Uri
, essayez d'abord d'utiliser
Uri uri = data.getData();
String src = uri.getPath();
où data
est le Intent
renvoyé dans onActivityResult()
.
Si cela ne fonctionne pas, utilisez la méthode suivante:
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);
}
Au moins une de ces deux méthodes devrait vous fournir le chemin d'accès correct et complet.
ÉTAPE 3 - Copiez le fichier:
Ce que vous voulez, je crois, c'est copier un fichier d'un endroit à un autre.
Pour ce faire, il est nécessaire d'avoir le chemin de fichier absolu des emplacements source et destination.
Tout d'abord, obtenez le chemin absolu du fichier à l'aide de ma méthode getPath()
ou uri.getPath()
:
String src = getPath(uri); /* Method defined above. */
ou
Uri uri = data.getData();
String src = uri.getPath();
Ensuite, créez deux objets File
comme suit:
File source = new File(src);
String filename = uri.getLastPathSegment();
File destination = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/CustomFolder/" + filename);
où CustomFolder
est le répertoire sur votre lecteur externe où vous souhaitez copier le fichier.
Utilisez ensuite la méthode suivante pour copier un fichier d'un endroit à un autre:
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();
}
}
Essaye ça. Cela devrait fonctionner.
Remarque: Vis-à-vis de la réponse de Lukas - ce qu'il a fait, c'est utiliser une méthode appelée openInputStream()
qui renvoie le content d'un Uri
, que ce Uri
représente un fichier ou une URL.
Une autre approche prometteuse - le FileProvider
:
Il existe un autre moyen par lequel il est possible d'obtenir un fichier à partir d'une autre application. Si une application partage ses fichiers via FileProvider
, il est possible d'obtenir un objet FileDescriptor
contenant des informations spécifiques sur ce fichier.
Pour ce faire, utilisez le Intent
suivant:
Intent mRequestFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
mRequestFileIntent.setType("*/*");
startActivityForResult(mRequestFileIntent, 0);
et dans votre 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();
...
}
}
où mInputPFD
est un ParcelFileDescriptor
.
Références:
1. Intentions communes - Stockage de fichiers .
2. FileChannel
=.
3. FileProvider
=.
J'ai fait de même pour laisser l'utilisateur choisir une image dans un dossier:
1) il y a un bouton OUVERT:
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_open:
myOpenImagePicker();
break;
}
}
2) la fonction de dossier d'image ouverte:
@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);
}
}
) le résultat de l'activité où j'obtiens le chemin du fichier image et fais ce que je veux avec le chemin de l'image:
@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) et maintenant la PARTIE LA PLUS IMPORTANTE, la classe W_ImgFilePathUtil, le code ne vient pas de moi mais il vous permet de récupérer le chemin complet de tout fichier sélectionné que ce soit sur carte sd, google drive, ... :
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());
}
}
CONCLUSION: le code fonctionne avec le chemin de l'image mais fonctionne bien avec tout type de fichier.
J'espère que cela vous aidera à résoudre votre problème.
PAIX.
Comme @ CommonsWare déjà noté, Android vous renvoie un Uri
, qui est un concept plus abstrait qu'un chemin de fichier.
Il peut également décrire un chemin de fichier simple, mais il peut également décrire une ressource accessible via une application (comme content://media/external/audio/media/710
).
Si vous souhaitez que votre utilisateur choisisse un fichier du téléphone pour le lire dans votre application, vous pouvez le faire en demandant le fichier (comme vous l'avez fait correctement), puis utilisez le ContentResolver
pour obtenir un InputStream
pour le Uri
renvoyé par le sélecteur.
Voici un exemple:
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();
}
}
}
}
}
Important: Certains fournisseurs (comme Dropbox) stockent/mettent en cache leurs données sur le stockage externe. Vous devrez avoir le Android.permission.READ_EXTERNAL_STORAGE
- autorisation déclarée dans votre manifeste, sinon vous obtiendrez FileNotFoundException
, même si le fichier est là.
pdate: Oui, vous pouvez copier le fichier en le lisant d'un flux et en l'écrivant sur un autre:
// 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 suppression du fichier n'est probablement pas possible, car le fichier ne vous appartient pas , il appartient à l'application qui l'a partagé avec le vôtre. À cet effet, l'application propriétaire est responsable de la suppression du fichier.
Passez l'URI retourné dans onActivityResult dans cette méthode
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;
}
n Uri
n'est pas un fichier . Un Uri
est plus proche d'une URL de serveur Web. C'est une adresse opaque, qui n'a de sens que pour le "serveur" (ou dans ce cas, le ContentProvider
).
Tout comme vous utilisez un InputStream
pour lire les octets représentés par une URL Web, vous utilisez un InputStream
pour lire les octets représentés par le Uri
. Vous obtenez un tel flux en appelant openInputStream()
sur un ContentResolver
.