简体   繁体   English

如何将 TXT 文件写入“/storage/emulated/0/myapp/myfile.txt”,以便稍后从文件浏览器打开它们?

[英]How can I write TXT files to "/storage/emulated/0/myapp/myfile.txt" so I can open them from file browser later?

I want the TXT files (and the folder containing them) generated by my App to be accessible by my phone's file browser, or even from a PC when I plug the phone via USB.我希望我的应用程序生成的 TXT 文件(以及包含它们的文件夹)可以通过我手机的文件浏览器访问,甚至当我通过 USB 插入手机时可以从 PC 访问。 Android's official documentation describes the different types of storing depending if it is "internal" or "external" (Google's terminology). Android 的官方文档描述了不同类型的存储,具体取决于它是“内部”还是“外部”(Google 的术语)。 And of course, I don't want those TXT files to be deleted when I uninstall the App.当然,我不希望卸载应用程序时删除那些 TXT 文件。

To avoid any confusions:为避免任何混淆:

The fact that I want to hardcode the file location in the App, doesn't imply that I would use neccessarily the complete absolute filepath as a parameter.我想对应用程序中的文件位置进行硬编码这一事实并不意味着我必须使用完整的绝对文件路径作为参数。 What i mean is the relative filepath will be hardcoded (same task, same file, same place).我的意思是相对文件路径将被硬编码(相同的任务,相同的文件,相同的位置)。

...that said... ……那说……

The app is for personal use (I mean to use it myself), so fulfilling Google Play Store's requirements is not a priority for now.该应用程序供个人使用(我的意思是自己使用),因此满足 Google Play 商店的要求目前不是优先事项。

Code example (what I tried)代码示例(我尝试过的)

 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

It would be Python on PC, stuff's done in 5 minutes!!这将是 PC 上的 Python,5 分钟内完成! 3 hours and I still can't figure it out?? 3个小时,我还是想不通?? I wanna cry...我想哭...

So, I want to save some output always in the same file, in the same path .所以,我想总是在同一个文件中保存一些输出,在同一个路径中 And I want that TXT file to be accessible from my PC when I plug it in via USB, as well as from my phone's file browser.我希望当我通过 USB 插入我的 PC 以及从我手机的文件浏览器时,可以从我的 PC 访问该 TXT 文件。 In Python, for example, for a PC app, I would achieve this with 3 single lines of code!例如,在 Python 中,对于 PC 应用程序,我会用 3 行代码来实现这一点! It can't be much harder in Android, right?在 Android 中不会更难,对吧? (or so I hope) (或者我希望如此)

I am aware that, for what I describe here, it is technically "documents and other kind of files", and what Google or Android Developers consider "external storage" (but what Android Users consider Internal Storage!).我知道,对于我在这里描述的内容,它在技术上是“文档和其他类型的文件”,以及 Google 或 Android 开发人员认为的“外部存储”(但 Android 用户认为的内部存储!)。 Well, Android Developers Documentation has a section for this in this link .好吧,Android 开发人员文档在此链接中有一个部分。

But the example's Code Snippet is overkill for my needs: I don't want the User to choose filepath: I want to hardcode the TXT files' paths into /storage/emulated/0/myapp/ directory.但是示例的代码片段对于我的需求来说太过分了:我不希望用户选择文件路径:我想将 TXT 文件的路径硬编码到/storage/emulated/0/myapp/目录中。 Instead, the example seems to provide some way to open some kind of "Save As" file dialog, which I don't want .相反,该示例似乎提供了某种方法来打开某种我不想要的“另存为”文件对话框。

According to this article , it suggests me to use Environment.getExternalStoragePublicDirectory , and if I look to this method's documentation it says this method is deprecated from API 28. I have been looking other docs about the subject, but I am still confused about how to proceed.根据这篇文章,它建议我使用Environment.getExternalStoragePublicDirectory ,如果我查看此方法的文档,它说此方法已从 API 28 中弃用。我一直在查看有关该主题的其他文档,但我仍然对如何使用感到困惑继续。 Supposing that I already have the text I want to write into a String variable:假设我已经有了要写入String变量的文本:

  1. How would I make sure that files would be written to some dedicated folder like /storage/emulated/0/myapp or /storage/emulated/0/myfolder instead of the root folder /storage/emulated/0 ?我如何确保将文件写入某个专用文件夹,例如/storage/emulated/0/myapp/storage/emulated/0/myfolder而不是根文件夹/storage/emulated/0 Will getExternalFilesDir() return /storage/emulated/0 or is there a better method? getExternalFilesDir()返回/storage/emulated/0还是有更好的方法?

  2. Which is the simplest code to just write the file containing the String variable's text with a hardcoded filename into the dedicated directory, but it will still persist after desinstalling the app?哪个是将包含带有硬编码文件名的String变量文本的文件写入专用目录的最简单代码,但在卸载应用程序后它仍然存在?

If it is either /storage/emulated/0 or /storage/emulated/0/Documents , any of both is fine by me.如果它是/storage/emulated/0/storage/emulated/0/Documents ,我认为两者都可以。 The most important thing is that I can access those files from outside my App that is gonna make them and, if possible , that uninstalling the mentioned App won't delete them.最重要的是,我可以从我的应用程序外部访问这些文件,如果可能的话,卸载提到的应用程序不会删除它们。

Context.getExternalFilesDir(null) is the new alternative to Environment.getExternalStoragePublicDirectory() but as you mentioned this will return a directory that will get deleted once you uninstall the app. Context.getExternalFilesDir(null)Environment.getExternalStoragePublicDirectory()的新替代方案,但正如您提到的,这将返回一个目录,一旦您卸载应用程序,该目录就会被删除。 For your use case you need to use MediaStore and I completely agree with you: this has become terribly complicated (i think android has done this in order to strengten security and so that other apps can more easyly browse the files you place in shared directories).Here are some methods to do what you want using Media Store:对于您的用例,您需要使用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();
        }
       
    }

you will also need the following method to be able to acertain if the file already exists.您还需要以下方法才能确定文件是否已存在。 I made it it so it returns an Uri but you should change that to suit your needs我做了它所以它返回一个 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;
}

please do not forget to add the corresponding permissions to the manifest fro this to work:请不要忘记将相应的权限添加到清单中以使其工作:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

btw this answer does something similar顺便说一句, 这个答案做了类似的事情

Try this code, it saves data to file, but on internal storage.试试这个代码,它将数据保存到文件中,但保存在内部存储中。 It's more convenient, because a lot of devices now don't have external card.更方便,因为现在很多设备没有外卡。 You can extract that file at least using android emulator tools and save it to your PC:您至少可以使用 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();
    }
}

My experience in this area is limited however, I believe I have an answer.我在这方面的经验有限,但我相信我有答案。 Firstly, when using an android device and wishing to install anything to a root folder, you are required to have a rooted device.首先,当使用 android 设备并希望将任何东西安装到根文件夹时,您需要有一个根设备。 Another option (what I have done on my android 10 Lenovo Tab M10 FHD+) is forcing the app to store the information externally through the app itself and using a file manager (with root capabilities such as X-plore or others) to manually move the text files.另一种选择(我在我的 android 10 Lenovo Tab M10 FHD+ 上所做的)是强制应用程序通过应用程序本身在外部存储信息并使用文件管理器(具有根功能,如 X-plore 或其他)手动移动文本文件。

it is simple.很简单。 you are getting file not found that exception because:您正在获取文件未找到该异常,因为:

  1. you did not create the file yourself.您没有自己创建文件。
  2. you did not pass the CreateNew or CreateAppend parameter to the unused FileStream...您没有将CreateNewCreateAppend参数传递给未使用的FileStream...

Add these to your code:将这些添加到您的代码中:

To fix the FileNotFoundException:要修复 FileNotFoundException:

FileStream fs = new FileStream(filePath, FileMode.CreateNew);

To fix the Permission Issue:要修复权限问题:

FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, "your file's name plus extension(.txt)");

To create different files for you not to get lost between which file contains what link!, maybe use the name of the website you visited through the Split([4]) guessing you have www.websitename.domain , you can split the link at index 4 and get rid of the rest of the link!要创建不同的文件,以免在哪个文件包含哪个链接之间迷路!,也许使用您通过Split([4])访问的网站的名称猜测您有www.websitename.domain ,您可以在以下位置拆分链接索引 4 并删除链接的其余部分! or depend on your memory and remember when you created what file.或取决于您的记忆并记住您何时创建了什么文件。 😁 😁

string filename = DatTime.Now.ToShortDate.ToString() + ".txt";

Then use the filename in the filepath you've set.然后使用您设置的filename filepathfilename

Congrats your app is running, and it is fun 😊恭喜您的应用程序正在运行,很有趣😊

Best of luck mate ✌祝朋友好运✌

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 data / data / package / files / myfile.txt不会复制到apk文件 - data/data/package/files/myfile.txt is not copied to apk file 如何在某些框架目录下创建文件myfile.txt并将其压缩为Java - How to Create a file myfile.txt under some aribtrary directories and tar them in Java myfile.txt中没有任何内容 - nothing is present in myfile.txt 为什么会出现这个错误? :java.io.FileNotFoundException: /dir/myfile.txt(打开的文件太多) - why does this error occur? :java.io.FileNotFoundException: /dir/myfile.txt (Too many open files) 我怎样才能对象写入一个txt或者csv文件用? - How can I write an object into a txt or csv file with? 如何用Java写入在线服务器上存储的.txt文件? - How can i write to a .txt file stored on an online server in Java? 如何在Java中的txt文件中写入特定的行号 - How can I write to a specific line number in a txt file in Java 如何使DataOutputStream将布尔或整数写入txt文件? - How can I make DataOutputStream write a bool or integer to a txt file? 如何更改txt文件中的数据(字符串)以便我可以对该数据进行数学运算? - How to change data(string) from a txt file so I can do mathematical operations on that data? 如何从 .t​​xt 文件中读取数字并将它们放入二维数组中? - How can I read numbers from a .txt file and put them into a 2-D array?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM