Android应用自动上传内部存储文本文件至PHP服务器问题排查
问题解决:Android内部存储文件上传至PHP服务器
核心问题分析
你的代码存在两个关键问题导致上传失败:
- 文件路径错误:你使用了外部存储路径
Environment.getExternalStorageDirectory(),但目标文件位于App私有内部存储,路径不匹配; - 上传格式不兼容:PHP代码通过
$_FILES["fileToUpload"]接收表单式文件,而你的Android代码直接传递文件流,PHP无法识别该字段。
步骤1:正确获取内部存储文件路径
App私有内部存储的根目录为/data/data/[你的包名]/files/,无需申请权限即可访问,获取文件的代码如下:
在Activity中获取:
// 获取内部存储根目录下的textFile.txt File file = new File(getFilesDir(), "textFile.txt");
在Service/BroadcastReceiver中获取(需传入Context):
// 假设已有Context实例context File file = new File(context.getFilesDir(), "textFile.txt");
验证文件存在性:上传前先检查文件是否存在,避免空指针或找不到文件的问题:
if (!file.exists()) { Log.e("Upload", "目标文件不存在:" + file.getAbsolutePath()); return; }
步骤2:修改Android上传代码(适配PHP接收格式)
PHP需要接收multipart/form-data格式的表单数据,因此你需要改用Multipart方式上传。以下提供两种实现方案:
方案1:使用OkHttp(推荐,适配高版本Android)
OkHttp是Android官方推荐的网络库,替代已被弃用的DefaultHttpClient。
- 在
build.gradle(Module level)添加依赖:
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
- 异步上传代码(避免主线程阻塞):
String url = "https://path-to/file-upload3.php"; File file = new File(getFilesDir(), "textFile.txt"); if (!file.exists()) { Log.e("UploadError", "文件不存在:" + file.getAbsolutePath()); return; } OkHttpClient client = new OkHttpClient(); // 构建Multipart表单,字段名必须和PHP的"fileToUpload"一致 RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( "fileToUpload", file.getName(), RequestBody.create(file, MediaType.parse("text/plain")) ) .build(); Request request = new Request.Builder() .url(url) .post(requestBody) .build(); // 异步执行请求 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); Log.e("UploadFail", "上传失败:" + e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { String responseMsg = response.body().string(); Log.d("UploadSuccess", "服务器响应:" + responseMsg); } else { Log.e("UploadError", "服务器返回错误码:" + response.code()); } } });
方案2:使用Apache HttpClient(兼容旧版本)
如果必须使用DefaultHttpClient,需要引入依赖并修改上传逻辑:
- 添加依赖:
implementation 'org.apache.httpcomponents:httpmime:4.5.14' implementation 'org.apache.httpcomponents:httpclient-android:4.5.14'
- 上传代码(需放在子线程执行):
String url = "https://path-to/file-upload3.php"; File file = new File(getFilesDir(), "textFile.txt"); if (!file.exists()) { Log.e("UploadError", "文件不存在:" + file.getAbsolutePath()); return; } new Thread(new Runnable() { @Override public void run() { try { HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost(url); // 构建Multipart实体,字段名匹配PHP的fileToUpload MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addBinaryBody( "fileToUpload", file, ContentType.DEFAULT_BINARY, file.getName() ); httppost.setEntity(builder.build()); HttpResponse response = httpclient.execute(httppost); // 读取服务器响应 String responseMsg = EntityUtils.toString(response.getEntity(), "UTF-8"); Log.d("UploadResponse", responseMsg); } catch (Exception e) { e.printStackTrace(); Log.e("UploadException", e.getMessage()); } } }).start();
步骤3:修复PHP代码逻辑问题
你的PHP代码存在校验顺序错误(先上传后校验),且未确保uploads目录存在,修改后的代码如下:
<?php $target_dir = "uploads/"; // 确保uploads目录存在,不存在则创建 if (!file_exists($target_dir)) { mkdir($target_dir, 0777, true); } $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]); $uploadOk = 1; $imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION)); // 检查文件是否已存在 if (file_exists($target_file)) { echo "Sorry, file already exists."; $uploadOk = 0; } // 检查文件大小(限制500KB) if ($_FILES["fileToUpload"]["size"] > 500000) { echo "Sorry, your file is too large."; $uploadOk = 0; } // 允许的文件格式 $allowedTypes = array("jpg", "png", "jpeg", "gif", "txt"); if (!in_array($imageFileType, $allowedTypes)) { echo "Sorry, only JPG, JPEG, PNG, GIF and TXT files are allowed."; $uploadOk = 0; } // 执行上传或返回错误 if ($uploadOk == 0) { echo "Sorry, your file was not uploaded."; } else { if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) { echo "The file " . basename($_FILES["fileToUpload"]["name"]) . " has been uploaded."; } else { echo "Sorry, there was an error uploading your file."; } } ?>
额外注意事项
- 网络请求线程:Android禁止在主线程执行网络请求,必须将上传代码放在子线程(如OkHttp的异步回调、Thread、AsyncTask);
- 权限:内部存储无需任何权限,若后续切换到外部存储,需在AndroidManifest.xml添加权限并在高版本Android中申请动态权限;
- 调试:通过Logcat查看服务器响应信息,排查上传失败的具体原因(如文件不存在、服务器返回错误等)。
内容的提问来源于stack exchange,提问作者Inderjeet Singh
相关产品推荐
相关产品推荐

