我正在尝试在我的 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 answer 相同的方法,但我不知道是否可以通过它Copy
这个File
到我的SDcard
的另一部分,我正在等待他的回答。
@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()
来自@Y.S.
我正在这样做:
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: Failure delivering result 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
使用 @Y.S. 编辑代码, @Lukas Knuth , 和 @CommonsWare .
这是我只接受文件 text/plain
的 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
);
在我的 onActivityResult()
上,我创建了一个 URI
,在其中获取 Intent
的数据,我创建了一个 File
我保存 absolute path 执行 content_describer.getPath();
,然后我将路径的名称保留在 TextView
与 content_describer.getLastPathSegment();
(太棒了@Y.S. 不知道那个函数),我创建了第二个 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 文件
,如果它不存在我创建这个文件夹,如果它存在不是我什么都不做。
private void DirectoryExist (File destination) {
if(!destination.isDirectory()) {
if(destination.mkdirs()){
Log.d("Carpeta creada","....");
}else{
Log.d("Carpeta no creada","....");
}
}
再次感谢您的帮助,希望您喜欢与大家一起制作的这段代码 :)
最佳答案
第 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 步 - 获取绝对文件路径:
要从 Uri
获取文件路径,首先尝试使用
Uri uri = data.getData();
String src = uri.getPath();
其中 data
是 onActivityResult()
中返回的 Intent
。
如果不行,请使用以下方法:
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();
}
}
试试这个。这应该可以。
注意: Vis-a-vis Lukas 的回答 - 他所做的是使用一种名为 openInputStream()
的方法,该方法返回 content 的 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. Common Intents - File Storage .
2. FileChannel
.
3. FileProvider
.
关于android - 在 Android 中实现文件选择器并将所选文件复制到另一个位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30789116/