请求某个分享的文件
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
当应用想要访问其他应用共享的文件时,发出请求的应用(客户端)
通常会向共享文件的应用(服务器)发送请求。在大多数情况下,
在服务器应用中启动一个 Activity
,以显示可共享的文件。
用户选择文件后,服务器应用会将文件的内容 URI 返回给
。
本课将介绍客户端应用如何从服务器应用请求文件,以及如何接收文件的
内容 URI,并使用内容 URI 打开文件。
发送文件请求
如需从服务器应用请求文件,客户端应用调用
startActivityForResult
,具有
Intent
包含如下操作:
ACTION_PICK
以及客户端应用
例如,以下代码段展示了如何发送
Intent
到服务器应用,以便启动
共享文件中所述的 Activity
:
Kotlin
class MainActivity : Activity() {
private lateinit var requestFileIntent: Intent
private lateinit var inputPFD: ParcelFileDescriptor
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
requestFileIntent = Intent(Intent.ACTION_PICK).apply {
type = "image/jpg"
}
...
}
...
private fun requestFile() {
/**
* When the user requests a file, send an Intent to the
* server app.
* files.
*/
startActivityForResult(requestFileIntent, 0)
...
}
...
}
Java
public class MainActivity extends Activity {
private Intent requestFileIntent;
private ParcelFileDescriptor inputPFD;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestFileIntent = new Intent(Intent.ACTION_PICK);
requestFileIntent.setType("image/jpg");
...
}
...
protected void requestFile() {
/**
* When the user requests a file, send an Intent to the
* server app.
* files.
*/
startActivityForResult(requestFileIntent, 0);
...
}
...
}
访问请求的文件
服务器应用以
Intent
。此 Intent
会传递给客户端
替换 onActivityResult()
。一次
客户端应用具有文件的内容 URI,其可通过获取其
FileDescriptor
。
只有正确解析内容 URI 后,在此过程中才会保证文件安全性
唯一 ID解析内容时,必须确保此 URI 不指向
指定目录之外的任何内容,以确保
系统会尝试执行路径遍历。
只有客户端应用才可以访问该文件,且只能获得
服务器应用权限是临时的,因此在客户端应用的任务堆栈完成后,
文件无法再从服务器应用外部访问。
下一个代码段演示了客户端应用如何处理
从服务器应用发送的 Intent
,以及客户端应用如何获取
使用内容 URI 执行 FileDescriptor
:
Kotlin
/*
* When the Activity of the app that hosts files sets a result and calls
* finish(), this method is invoked. The returned Intent contains the
* content URI of a selected file. The result code indicates if the
* selection worked or not.
*/
public override fun onActivityResult(requestCode: Int, resultCode: Int, returnIntent: Intent) {
// If the selection didn't work
if (resultCode != Activity.RESULT_OK) {
// Exit without doing anything else
return
}
// Get the file's content URI from the incoming Intent
returnIntent.data?.also { returnUri ->
/*
* 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.
*/
inputPFD = try {
/*
* Get the content resolver instance for this context, and use it
* to get a ParcelFileDescriptor for the file.
*/
contentResolver.openFileDescriptor(returnUri, "r")
} catch (e: FileNotFoundException) {
e.printStackTrace()
Log.e("MainActivity", "File not found.")
return
}
// Get a regular file descriptor for the file
val fd = inputPFD.fileDescriptor
...
}
}
Java
/*
* When the Activity of the app that hosts files sets a result and calls
* finish(), this method is invoked. The returned Intent contains the
* content URI of a selected file. The result code indicates if the
* selection worked or not.
*/
@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.
*/
inputPFD = 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 = inputPFD.getFileDescriptor();
...
}
}
openFileDescriptor()
方法
会返回文件的 ParcelFileDescriptor
。在此对象中,客户端
应用会获取 FileDescriptor
对象,然后使用该对象读取文件。
如需了解其他相关信息,请参阅:
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[null,null,["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Requesting a shared file\n\nWhen an app wants to access a file shared by another app, the requesting app (the client)\nusually sends a request to the app sharing the files (the server). In most cases, the request\nstarts an [Activity](/reference/android/app/Activity) in the server app that displays the files it can share.\nThe user picks a file, after which the server app returns the file's content URI to the\nclient app.\n\n\nThis lesson shows you how a client app requests a file from a server app, receives the file's\ncontent URI from the server app, and opens the file using the content URI.\n\nSend a request for the file\n---------------------------\n\n\nTo request a file from the server app, the client app calls\n[startActivityForResult](/reference/android/app/Activity#startActivityForResult(android.content.Intent, int)) with an\n[Intent](/reference/android/content/Intent) containing the action such as\n[ACTION_PICK](/reference/android/content/Intent#ACTION_PICK) and a MIME type that the client app\ncan handle.\n\n\nFor example, the following code snippet demonstrates how to send an\n[Intent](/reference/android/content/Intent) to a server app in order to start the\n[Activity](/reference/android/app/Activity) described in [Sharing a file](/training/secure-file-sharing/share-file#SendURI): \n\n### Kotlin\n\n```kotlin\nclass MainActivity : Activity() {\n private lateinit var requestFileIntent: Intent\n private lateinit var inputPFD: ParcelFileDescriptor\n ...\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n setContentView(R.layout.activity_main)\n requestFileIntent = Intent(Intent.ACTION_PICK).apply {\n type = \"image/jpg\"\n }\n ...\n }\n ...\n private fun requestFile() {\n /**\n * When the user requests a file, send an Intent to the\n * server app.\n * files.\n */\n startActivityForResult(requestFileIntent, 0)\n ...\n }\n ...\n}\n```\n\n### Java\n\n```java\npublic class MainActivity extends Activity {\n private Intent requestFileIntent;\n private ParcelFileDescriptor inputPFD;\n ...\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n setContentView(R.layout.activity_main);\n requestFileIntent = new Intent(Intent.ACTION_PICK);\n requestFileIntent.setType(\"image/jpg\");\n ...\n }\n ...\n protected void requestFile() {\n /**\n * When the user requests a file, send an Intent to the\n * server app.\n * files.\n */\n startActivityForResult(requestFileIntent, 0);\n ...\n }\n ...\n}\n```\n\nAccess the requested file\n-------------------------\n\n\nThe server app sends the file's content URI back to the client app in an\n[Intent](/reference/android/content/Intent). This [Intent](/reference/android/content/Intent) is passed to the client\napp in its override of [onActivityResult()](/reference/android/app/Activity#onActivityResult(int, int, android.content.Intent)). Once\nthe client app has the file's content URI, it can access the file by getting its\n[FileDescriptor](/reference/java/io/FileDescriptor).\n\n\nFile security is preserved in this process only as long as you properly parse the content URI\nthat the client app receives. When parsing content, you must ensure that this URI does not point\nto anything outside of the intended directory, ensuring that no\n[path traversal](/privacy-and-security/risks/path-traversal) is being attempted.\nOnly the client app should gain access to the file, and only for the permissions granted by the\nserver app. Permissions are temporary, so once the client app's task stack is finished, the\nfile is no longer accessible outside the server app.\n\n\nThe next snippet demonstrates how the client app handles the\n[Intent](/reference/android/content/Intent) sent from the server app, and how the client app gets the\n[FileDescriptor](/reference/java/io/FileDescriptor) using the content URI: \n\n### Kotlin\n\n```kotlin\n/*\n * When the Activity of the app that hosts files sets a result and calls\n * finish(), this method is invoked. The returned Intent contains the\n * content URI of a selected file. The result code indicates if the\n * selection worked or not.\n */\npublic override fun onActivityResult(requestCode: Int, resultCode: Int, returnIntent: Intent) {\n // If the selection didn't work\n if (resultCode != Activity.RESULT_OK) {\n // Exit without doing anything else\n return\n }\n // Get the file's content URI from the incoming Intent\n returnIntent.data?.also { returnUri -\u003e\n /*\n * Try to open the file for \"read\" access using the\n * returned URI. If the file isn't found, write to the\n * error log and return.\n */\n inputPFD = try {\n /*\n * Get the content resolver instance for this context, and use it\n * to get a ParcelFileDescriptor for the file.\n */\n contentResolver.openFileDescriptor(returnUri, \"r\")\n } catch (e: FileNotFoundException) {\n e.printStackTrace()\n Log.e(\"MainActivity\", \"File not found.\")\n return\n }\n\n // Get a regular file descriptor for the file\n val fd = inputPFD.fileDescriptor\n ...\n }\n}\n```\n\n### Java\n\n```java\n /*\n * When the Activity of the app that hosts files sets a result and calls\n * finish(), this method is invoked. The returned Intent contains the\n * content URI of a selected file. The result code indicates if the\n * selection worked or not.\n */\n @Override\n public void onActivityResult(int requestCode, int resultCode,\n Intent returnIntent) {\n // If the selection didn't work\n if (resultCode != RESULT_OK) {\n // Exit without doing anything else\n return;\n } else {\n // Get the file's content URI from the incoming Intent\n Uri returnUri = returnIntent.getData();\n /*\n * Try to open the file for \"read\" access using the\n * returned URI. If the file isn't found, write to the\n * error log and return.\n */\n try {\n /*\n * Get the content resolver instance for this context, and use it\n * to get a ParcelFileDescriptor for the file.\n */\n inputPFD = getContentResolver().openFileDescriptor(returnUri, \"r\");\n } catch (FileNotFoundException e) {\n e.printStackTrace();\n Log.e(\"MainActivity\", \"File not found.\");\n return;\n }\n // Get a regular file descriptor for the file\n FileDescriptor fd = inputPFD.getFileDescriptor();\n ...\n }\n }\n```\n\n\nThe method [openFileDescriptor()](/reference/android/content/ContentResolver#openFileDescriptor(android.net.Uri, java.lang.String))\nreturns a [ParcelFileDescriptor](/reference/android/os/ParcelFileDescriptor) for the file. From this object, the client\napp gets a [FileDescriptor](/reference/java/io/FileDescriptor) object, which it can then use to read the file.\n\nFor additional related information, refer to:\n\n- [Intents and Intent Filters](/guide/components/intents-filters)\n- [Retrieving Data from the Provider](/guide/topics/providers/content-provider-basics#SimpleQuery)"]]