Ski*_*ᴉʞS 17 android android-intent android-file android-implicit-intent android-fileprovider
我正在尝试在我的Android项目中实现文件选择器.到目前为止我能做的是:
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);
然后在我的 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;
}
这是打开文件选择器,但它不是我想要的.例如,我想选择一个文件(.txt),然后获取它File然后使用它.有了这段代码,我想我会得到完整的路径,但它不会发生; 例如,我得到:/document/5318/.但是通过这条路径我无法获取文件.我创建了一个名为方法PathToFile()返回一个File:
 private File PathToFile(String path) {
    File tempFileToUpload;
    tempFileToUpload = new File(path);
    return tempFileToUpload;
}
我正在试图做的是让用户选择File从任何地方表示DropBox,Drive,SDCard,Mega,等...我没有找到正确方式做到这一点,我试图让Path然后得到一个File本Path...但它不起作用,所以我认为最好File自己动手,然后以File编程方式我Copy这个或者Delete.
我的 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
 );
在那里我有一个问题,因为我不知道支持的是什么text/plain,但我会调查它,但目前并不重要.
在我的onActivityResult()我用一样@Lukas Knuth的答案,但我不知道它,我可以Copy这样File给另一部分从我SDcard我waitting他的回答.
@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() 来自@YS 
我这样做:
    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));
得到一个NullPointerException:
java.lang.RuntimeException:将结果ResultInfo {who = null,request = 131073,result = -1,data = Intent {dat = file:/// path typ = text/plain flg = 0x3}}发送到activity {info .androidhive.tabsswipe/info.androidhive.tabsswipe.MainActivity2}:java.lang.NullPointerException
这是Intent我只接受文件的地方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
);
在我的onActivityResult()我创建一个URI在那里我得到的数据Intent,我创建了一个File在我保存绝对路径做content_describer.getPath();,然后我把路径的名称在使用它TextView与content_describer.getLastPathSegment();(这是真棒@YS不知道那个函数),我创建了一个File我调用的第二个,destination我发送AbsolutePath给它可以创建它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);
    }
}
此外,我已经创建了你需要发送的功能source file,而且destination file我们先前创建的这个复制到新的文件夹.
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();
    }
}
另外我已经创建了一个函数,告诉我这个文件夹是否存在(我必须发送destination file,如果它不存在我创建这个文件夹,如果不存在我什么都不做.
private void DirectoryExist (File destination) {
    if(!destination.isDirectory()) {
        if(destination.mkdirs()){
            Log.d("Carpeta creada","....");
        }else{
            Log.d("Carpeta no creada","....");
        }
    }
再次感谢您的帮助,希望您喜欢与大家一起制作的代码:)
Y.S*_*Y.S 35
第1步 - 使用隐含Intent:
要从设备中选择文件,您应该使用隐式文件 Intent
Intent chooseFile = new Intent(Intent.ACTION_GET_CONTENT);
chooseFile.setType("*/*");
chooseFile = Intent.createChooser(chooseFile, "Choose a file");
startActivityForResult(chooseFile, PICKFILE_RESULT_CODE);
第2步 - 获取绝对文件路径:
要从a获取文件路径Uri,请先尝试使用
Uri uri = data.getData();
String src = uri.getPath();
这里data是Intent在返回onActivityResult().
如果这不起作用,请使用以下方法:
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);
}
这两种方法中至少有一种应该为您提供正确的完整路径.
第3步 - 复制文件:
我相信,你想要的是将文件从一个位置复制到另一个位置.
要做到这一点,绝对有必要拥有源位置和目标位置的绝对文件路径.
首先,使用我的getPath()方法获取绝对文件路径或uri.getPath():
String src = getPath(uri);    /* Method defined above. */
要么
Uri uri = data.getData();
String src = uri.getPath();
然后,创建两个File对象,如下所示:
File source = new File(src);
String filename = uri.getLastPathSegment();
File destination = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/CustomFolder/" + filename);
这里CustomFolder是你要复制的文件,你的外部驱动器上的目录.
然后使用以下方法将文件从一个位置复制到另一个位置:
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();
   }
}
试试这个.这应该工作.
注:面对面的人卢卡斯的回答-他所做的事是使用一种称为方法openInputStream()返回的内容的Uri,不管是Uri代表一个文件或URL.
另一个有前途的方法 - FileProvider:
还有一种方法可以从另一个应用程序获取文件.如果应用程序通过FileProvider它共享其文件,则可以获取FileDescriptor包含有关此文件的特定信息的对象.
为此,请使用以下命令Intent:
Intent mRequestFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
mRequestFileIntent.setType("*/*");
startActivityForResult(mRequestFileIntent, 0);
在你的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();
        ...
    }
}
这里mInputPFD是一个ParcelFileDescriptor.
参考文献:
1. 共同意图 - 文件存储.
2 FileChannel.
3 FileProvider.
4. 请求共享文件.
Mar*_*ler 10
有了ActivityResultLauncher它,它的工作方式就像这样:
ActivityResultLauncher<Intent> startActivityForResult = requireActivity().registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
    if (result.getResultCode() == Activity.RESULT_OK) {
        Intent data = result.getData();
        Uri contentUri = data.getData();
        ...
    }
});
使用示例:
Intent data = new Intent(Intent.ACTION_GET_CONTENT);
data.addCategory(Intent.CATEGORY_OPENABLE);
data.setType("*/*");
Intent intent = Intent.createChooser(data, "Choose a file");
startActivityForResult.launch(intent);
需要以下依赖项(带或不带-ktx):
implementation "androidx.activity:activity:1.5.0"
正如@CommonsWare已经指出的,Android向您返回Uri,这是比文件路径更抽象的概念。
它也可以描述一个简单的文件路径,但是它也可以描述通过应用程序(如content://media/external/audio/media/710)访问的资源。
如果你希望你的用户挑选来自手机的任何文件从您的应用程序读取它,你可以通过询问的文件(如你做正确的)这样做,然后使用ContentResolver得到一个InputStream对Uri由该选择器返回。
这是一个例子:
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();
                }
            }
        }
    }
}
重要提示:某些提供程序(如Dropbox)将其数据存储/缓存在外部存储中。您需要在android.permission.READ_EXTERNAL_STORAGE清单中声明-permission,否则FileNotFoundException即使文件已存在,也将得到。
更新:是的,您可以通过从一个流中读取文件并将其写入另一个文件来复制文件:
// 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();
    }
}
删除文件可能是不可能的,因为该文件不属于您,它属于与您共享文件的应用程序。因此,拥有的应用程序负责删除文件。
我做了同样的事情让用户从文件夹中选择一个图像:
1)有一个按钮OPEN:
@Override
public void onClick(View v) {
    switch (v.getId()) {
    case R.id.btn_open:
        myOpenImagePicker();
        break;
    }
}
2)打开图像文件夹功能:
@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)活动结果,我得到图像文件路径,并用图像路径做我想做的事情:
@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)现在最重要的部分,W_ImgFilePathUtil类,代码不是来自我,但它允许您检索任何选定文件的完整路径,无论是在SD卡,谷歌驱动器,...:
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());
    }
}
结论:代码适用于图像路径,但确实适用于任何类型的文件.
希望这有助于解决您的问题.
和平.
| 归档时间: | 
 | 
| 查看次数: | 27039 次 | 
| 最近记录: |