![](/img/trans.png)
[英]data/data/package/files/myfile.txt is not copied to apk file
[英]How can I write TXT files to "/storage/emulated/0/myapp/myfile.txt" so I can open them from file browser later?
我希望我的应用程序生成的 TXT 文件(以及包含它们的文件夹)可以通过我手机的文件浏览器访问,甚至当我通过 USB 插入手机时可以从 PC 访问。 Android 的官方文档描述了不同类型的存储,具体取决于它是“内部”还是“外部”(Google 的术语)。 当然,我不希望卸载应用程序时删除那些 TXT 文件。
我想对应用程序中的文件位置进行硬编码这一事实并不意味着我必须使用完整的绝对文件路径作为参数。 我的意思是相对文件路径将被硬编码(相同的任务,相同的文件,相同的位置)。
该应用程序供个人使用(我的意思是自己使用),因此满足 Google Play 商店的要求目前不是优先事项。
try {
// Dedicated folder would be better...
// ...but not even in the root folder works...
// FIXME T_T
FileWriter writer = new FileWriter("/storage/emulated/0/myfile.txt");
writer.write(my_string_for_file);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
// ...always throws FileNotFoundException with Permission DENIED
这将是 PC 上的 Python,5 分钟内完成! 3个小时,我还是想不通?? 我想哭...
所以,我想总是在同一个文件中保存一些输出,在同一个路径中。 我希望当我通过 USB 插入我的 PC 以及从我手机的文件浏览器时,可以从我的 PC 访问该 TXT 文件。 例如,在 Python 中,对于 PC 应用程序,我会用 3 行代码来实现这一点! 在 Android 中不会更难,对吧? (或者我希望如此)
我知道,对于我在这里描述的内容,它在技术上是“文档和其他类型的文件”,以及 Google 或 Android 开发人员认为的“外部存储”(但 Android 用户认为的内部存储!)。 好吧,Android 开发人员文档在此链接中有一个部分。
但是示例的代码片段对于我的需求来说太过分了:我不希望用户选择文件路径:我想将 TXT 文件的路径硬编码到/storage/emulated/0/myapp/
目录中。 相反,该示例似乎提供了某种方法来打开某种我不想要的“另存为”文件对话框。
根据这篇文章,它建议我使用Environment.getExternalStoragePublicDirectory
,如果我查看此方法的文档,它说此方法已从 API 28 中弃用。我一直在查看有关该主题的其他文档,但我仍然对如何使用感到困惑继续。 假设我已经有了要写入String
变量的文本:
我如何确保将文件写入某个专用文件夹,例如/storage/emulated/0/myapp
或/storage/emulated/0/myfolder
而不是根文件夹/storage/emulated/0
? getExternalFilesDir()
返回/storage/emulated/0
还是有更好的方法?
哪个是将包含带有硬编码文件名的String
变量文本的文件写入专用目录的最简单代码,但在卸载应用程序后它仍然存在?
如果它是/storage/emulated/0
或/storage/emulated/0/Documents
,我认为两者都可以。 最重要的是,我可以从我的应用程序外部访问这些文件,如果可能的话,卸载提到的应用程序不会删除它们。
Context.getExternalFilesDir(null)
是Environment.getExternalStoragePublicDirectory()
的新替代方案,但正如您提到的,这将返回一个目录,一旦您卸载应用程序,该目录就会被删除。 对于您的用例,您需要使用MediaStore
,我完全同意您的看法:这变得非常复杂(我认为 android 这样做是为了加强安全性,以便其他应用程序可以更轻松地浏览您放置在共享目录中的文件) .这里有一些方法可以使用 Media Store 执行您想要的操作:
private void saveTxtFile(String fileName, String fileContent, Context context) throws IOException {
OutputStream fos;
try{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName); //file name
values.put(MediaStore.MediaColumns.MIME_TYPE, "text/plain"); //file extension, will automatically add to file
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOCUMENTS + "/yourFolder/"); //end "/" is not mandatory
Uri uri = context.getContentResolver().insert(MediaStore.Files.getContentUri("external"), values); //important!
fos = context.getContentResolver().openOutputStream(uri);
} else {
String docsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString();
File file = new File(docsDir, fileName);
fos=new FileOutputStream(file);
}
try {
fos.write(fileContent.getBytes());
} finally {
fos.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
您还需要以下方法才能确定文件是否已存在。 我做了它所以它返回一个 Uri 但你应该改变它以满足你的需要
private Uri isFilePresent(String fileName, Context context) {
Uri contentUri = MediaStore.Files.getContentUri("external");
String selection = MediaStore.MediaColumns.RELATIVE_PATH + "=?";
String[] selectionArgs = new String[]{Environment.DIRECTORY_DOCUMENTS + "/yourFolder/"};
Cursor cursor = context.getContentResolver().query(contentUri, null, selection, selectionArgs, null);
Uri uri = null;
if (cursor.getCount() == 0) {
Toast.makeText(context, "No file found in " + Environment.DIRECTORY_DOCUMENTS + "yourFolder", Toast.LENGTH_LONG).show();
} else {
while (cursor.moveToNext()) {
String file = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME));
if (fileName.equals(fileName)) {
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
uri = ContentUris.withAppendedId(contentUri, id);
break;
}
}
}
return uri;
}
请不要忘记将相应的权限添加到清单中以使其工作:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
顺便说一句, 这个答案做了类似的事情
试试这个代码,它将数据保存到文件中,但保存在内部存储中。 更方便,因为现在很多设备没有外卡。 您至少可以使用 android 模拟器工具提取该文件并将其保存到您的 PC:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class FileManager {
public static void writeToFile(String fileName, String data, Context context) {
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(fileName, Context.MODE_PRIVATE));
outputStreamWriter.write(data);
outputStreamWriter.close();
} catch (FileNotFoundException e) {
LLog.e(e, "File not found");
} catch (IOException e) {
LLog.e(e, "File write failed");
}
}
public static void addToFile(String fileName, String data, Context context) {
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(fileName, Context.MODE_APPEND));
outputStreamWriter.append(data);
outputStreamWriter.close();
} catch (FileNotFoundException e) {
LLog.e(e, "File not found");
} catch (IOException e) {
LLog.e(e, "File write failed");
}
}
public static String readFromFile(String fileName, Context context) {
String resultStr = "";
try {
InputStream inputStream = context.openFileInput(fileName);
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ((receiveString = bufferedReader.readLine()) != null) {
stringBuilder.append(receiveString);
}
inputStream.close();
bufferedReader.close();
resultStr = stringBuilder.toString();
}
} catch (FileNotFoundException e) {
LLog.e(e, "File not found");
} catch (IOException e) {
LLog.e(e, "File write failed");
}
return resultStr;
}
public static String readFromFileInRawFolder(String fileName, Context context) {
String resultStr = "";
try {
InputStream inputStream = context.getResources().openRawResource(
context.getResources().getIdentifier(fileName, "raw", context.getPackageName()));
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String receiveString;
StringBuilder stringBuilder = new StringBuilder();
while ((receiveString = bufferedReader.readLine()) != null) {
stringBuilder.append(receiveString);
}
inputStream.close();
bufferedReader.close();
resultStr = stringBuilder.toString();
} catch (FileNotFoundException e) {
LLog.e(e, "File not found");
} catch (IOException e) {
LLog.e(e, "File write failed");
}
return resultStr;
}
public static boolean deleteFile(String fileName, Context context) {
File dir = context.getFilesDir();
File file = new File(dir, fileName);
return file.delete();
}
}
我在这方面的经验有限,但我相信我有答案。 首先,当使用 android 设备并希望将任何东西安装到根文件夹时,您需要有一个根设备。 另一种选择(我在我的 android 10 Lenovo Tab M10 FHD+ 上所做的)是强制应用程序通过应用程序本身在外部存储信息并使用文件管理器(具有根功能,如 X-plore 或其他)手动移动文本文件。
很简单。 您正在获取文件未找到该异常,因为:
CreateNew
或CreateAppend
参数传递给未使用的FileStream...
将这些添加到您的代码中:
要修复 FileNotFoundException:
FileStream fs = new FileStream(filePath, FileMode.CreateNew);
要修复权限问题:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, "your file's name plus extension(.txt)");
要创建不同的文件,以免在哪个文件包含哪个链接之间迷路!,也许使用您通过Split([4])
访问的网站的名称猜测您有www.websitename.domain ,您可以在以下位置拆分链接索引 4 并删除链接的其余部分! 或取决于您的记忆并记住您何时创建了什么文件。 😁
string filename = DatTime.Now.ToShortDate.ToString() + ".txt";
然后使用您设置的filename
filepath
的filename
。
恭喜您的应用程序正在运行,很有趣😊
祝朋友好运✌
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.