Android程序创建的外部存储文件无法在Windows资源管理器显示及FTP上传失败求助
问题描述
我是Android开发新手,程序需要创建HTML文件并上传至FTP服务器。手动创建目录和文件时一切正常,但通过代码创建后,Android Studio的Explorer能看到文件在正确目录,Windows资源管理器却看不到对应的目录和文件,推测这导致了FTP上传失败。查阅多篇存储相关文章仍无法解决,请求帮助。我希望能在Windows资源管理器中看到代码创建的文件夹内容。
相关代码
创建本地HTML文件方法
public void createLocalHTML(String codeRes, Context context) throws IOException { @SuppressLint("SdCardPath") File internalDir = new File(Environment.getExternalStorageDirectory() + File.separator + "timetracker" + File.separator + getYear() + File.separator + getMonth()); Log.d("localDir", String.valueOf(internalDir)); String fileName = codeRes + ".html"; File internalFile = new File(internalDir, fileName); Log.d("localDir", String.valueOf(internalFile)); if (internalFile.exists()) { Log.d("localDir", "file.exists TRUE"); if (internalFile.canRead()) { Log.d("localDir", "file.canRead TRUE"); } else { Log.d("localDir", "file.canRead FALSE"); } // update file in future.... } else {Log.d("localDir", "file.exists FALSE");} if (!internalDir.mkdirs()) { internalDir.mkdirs(); Log.d("mLog", "Directory created in path: " + internalDir); } else { return; } internalFile.createNewFile(); FileWriter writer = new FileWriter(fileName, false); writer.write(context.getAssets().open("dataTime.html").toString()); writer.close(); }
FTP上传文件方法
public void sendFileIntoFTP(FTPClient ftpClient, String codeRes) throws URISyntaxException, IOException { @SuppressLint("SdCardPath") String sourceFilePath = Environment.getExternalStorageDirectory() + File.separator + "timetracker" + File.separator + getYear() + File.separator + getMonth(); // Log.d("dirFTP", sourceFilePath); String fileName = codeRes + ".html"; File sourceFile = new File(new URI(sourceFilePath)); Log.d("dirFTP", String.valueOf(sourceFile)); InputStream inputStream = new FileInputStream(sourceFile); ftpClient.storeFile(fileName, inputStream); if (ftpClient.storeFile(fileName, inputStream)) { Log.d("dirFTP", "SUCCESS"); } else { Log.d("dirFTP", "ERROR"); } inputStream.close(); }
日志输出(localDir)
2023-11-14 10:44:44.567 6819-6945 localDir pid-6819 D /storage/emulated/0/timetracker/2023/11-2023 2023-11-14 10:44:44.567 6819-6945 localDir pid-6819 D /storage/emulated/0/timetracker/2023/11-2023/003.html 2023-11-14 10:44:44.572 6819-6945 localDir pid-6819 D file.exists TRUE 2023-11-14 10:44:44.573 6819-6945 localDir pid-6819 D file.canRead TRUE
权限配置
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
问题分析与解决方案
1. 文件写入路径错误
createLocalHTML方法中,FileWriter writer = new FileWriter(fileName, false);仅传入文件名,未指定完整路径,导致文件实际写入应用工作目录,而非目标外部存储路径。这是Windows资源管理器看不到文件、FTP上传失败的核心原因。
修复:使用完整文件路径初始化FileWriter:
FileWriter writer = new FileWriter(internalFile, false);
2. 目录创建逻辑错误
当前代码中,若目录已存在或创建成功,会直接return,导致后续文件创建、写入操作完全跳过。
修复:调整目录判断逻辑,仅在目录创建失败时返回:
if (!internalDir.exists()) { if (internalDir.mkdirs()) { Log.d("mLog", "Directory created in path: " + internalDir); } else { Log.d("mLog", "Failed to create directory"); return; } }
3. FTP上传路径错误
sendFileIntoFTP方法中,sourceFilePath是目录路径而非文件路径,导致FileInputStream打开的是目录而非目标HTML文件;且重复调用storeFile会因输入流已耗尽导致第二次上传失败。
修复:拼接完整文件路径,仅调用一次storeFile:
String fileName = codeRes + ".html"; String sourceFilePath = Environment.getExternalStorageDirectory() + File.separator + "timetracker" + File.separator + getYear() + File.separator + getMonth() + File.separator + fileName; File sourceFile = new File(sourceFilePath); Log.d("dirFTP", String.valueOf(sourceFile)); if (!sourceFile.exists()) { Log.d("dirFTP", "File not found"); return; } InputStream inputStream = new FileInputStream(sourceFile); boolean success = ftpClient.storeFile(fileName, inputStream); if (success) { Log.d("dirFTP", "SUCCESS"); } else { Log.d("dirFTP", "ERROR"); } inputStream.close();
4. 媒体库刷新(解决Windows可见性)
Android 10+的Scoped Storage机制下,新创建的文件不会自动被媒体库索引,导致Windows通过MTP连接时无法看到。需手动通知媒体库扫描:
在文件创建完成后添加:
MediaScannerConnection.scanFile(context, new String[]{internalFile.getAbsolutePath()}, null, (path, uri) -> Log.d("localDir", "File scanned: " + path));
5. 运行时权限检查
需确保在运行时获取对应存储权限:
- Android 6-9:请求
WRITE_EXTERNAL_STORAGE权限 - Android 10+:引导用户开启
MANAGE_EXTERNAL_STORAGE权限
示例代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent); } } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100); }
内容的提问来源于stack exchange,提问作者Alexandr Borisov

