在Android应用程序中读取文件需要花费太多时间

时间:2012-11-27 11:13:36

标签: java android file-io

我正在为Android编写一个Hangman应用程序,但我遇到了一些加载问题。 当我的应用程序启动时,我生成一个从txt文件中挑选的随机单词。问题是这个文件很重:它有近360'000个单词(4000 kB),因此选择一个单词需要10到20秒的时间,我知道这是因为我每次都读取文件并选择一个单词我点击Generate。

如果我在应用程序启动后读取文件并将其内容放入字符串数组中,这会是一件好事吗?我真的不知道数组是否可以处理这么多。 否则什么是好模式?

感谢阅读。

6 个答案:

答案 0 :(得分:1)

将其存储为CSV(逗号分隔值)。打开读取流,寻找随机位置并读取一小块字符,直到您点击','两次。现在,从您阅读的字符串中的逗号之间提取该单词。你也可以有一个自定义分隔符,如'#'或'|'而不是逗号。

更新:使用RandomAccessFile

Update2:readLine()使每行存储一个单词变得更加容易。即以\n

分隔

答案 1 :(得分:0)

您可以(也可能最好)创建单词数据库并查询随机单词。您可以先阅读Saving Data in SQL Databases

答案 2 :(得分:0)

将整个文件读入字符串数组不是一个好策略,因为这会占用大量内存。一个简单的解决方案是将大文件分成几个单独的文件(使用文件名的模式,如words1.txt,words2.txt等)。绘制单词时,首先选择文件,然后从文件中选择实际单词。

答案 3 :(得分:0)

文件读取是一项昂贵的操作,花费这么长时间是正常的。您应该创建一组文件而不是一个文件,每次启动应用程序时,都可以选择随机文件和随机文字。这应该减少所需的时间。

此外,您可以将单词名称存储在XML文件中,作为进入/ res / values /文件夹的App资源。您可以创建字符串数组资源并轻松从代码中获取它,而无需担心打开/关闭/读取文件。这非常简单。但是,将所有单词拆分为不同的xml文件(或至少是字符串数组)同样重要。在这里阅读更多。 http://developer.android.com/guide/topics/resources/string-resource.html#StringArray

或者另一种方法是通过从文件中读取数据将所有内容存储到数据库中。这样,只需首次启动应用程序即可。您可以在显示消息时显示“准备数据库...”或类似的消息。

答案 4 :(得分:0)

执行代码以在AsyncTask中解析/加载内容形式json / db以获得更快的速度。我加载5000行,每行约400个字符。没有AsyncTask就需要更长的时间。

    private class YourTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... s) {

            //Here you have to make the loading / parsing tasks
            //Don't call any UI actions here. For example a Toast.show() this will couse Exceptions
            // UI stuff you have to make in onPostExecute method

        }

        @Override
        protected void onPreExecute() {
            // This method will called during doInBackground is in process
            // Here you can for example show a ProgressDialog
        }

        @Override
        protected void onPostExecute(Long result) {
            // onPostExecute is called when doInBackground finished
            // Here you can for example fill your Listview with the content loaded in doInBackground method

        }

}

执行你只需要打电话:

new YourTask().execute("");

在这里,您可以了解有关AsyncTasks的更多信息:

AsyncTask developer Guide

答案 5 :(得分:0)

有些事情需要注意:

  1. 如果您的应用程序从SD卡读取,SD卡的质量实际上是一个因素 - 根据您使用的SD卡的等级,有不同的读/写速度 - 看它起来。

  2. 您提到每次单击“生成”时都会在文件中选择随机行 - 因为您可以确定用户将单击“生成”多次,这是一个好主意要读取该文件一次,将内容存储在某处(sqlite),下次需要获取随机单词时,从存储的数据中获取。通过这种方式,您可以限制从外部存储(在移动标准中,这是一项繁重的任务)中读取的次数,即每次启动应用程序的次数。

  3. 您甚至可以在文件上放置一个标记,以告知您内容是否已更改。从随机字符串到当前日期到md5校验和的任何内容都应该让您知道您不需要再次读取该文件,因为您之前已经读过它并将内容存储在您的sqlite数据库中。你想把它放在你文件的第一行。

  4. 既然其他人都在告诉你要考虑写一个sqlite数据库,甚至自己复制一个.db文件(你可以单独生成),那么选择一个随机项是微不足道的。我宁愿警告你在数据库中写入360,000个条目。使用默认的ContentProvider insert(Uri, ContentValues)方法可行,但如果花费的时间比实际解析文件本身要长,我会感到惊讶。这里的技巧是使用编译语句来覆盖ContentProvider的bulkInsert(Uri, ContentValues[])的实现。默认实现仅多次调用insert方法,因此每次插入时都会打开和关闭SqliteDatabase对象。您要执行的操作是在顶部调用beginTransaction,使用insert对ContentValues中的每个项目进行for循环,setTransactionSuccessful,然后调用endTransaction

相关问题