从资产中读取文件
Posted
技术标签:
【中文标题】从资产中读取文件【英文标题】:read file from assets 【发布时间】:2012-03-21 15:09:27 【问题描述】:public class Utils
public static List<Message> getMessages()
//File file = new File("file:///android_asset/helloworld.txt");
AssetManager assetManager = getAssets();
InputStream ims = assetManager.open("helloworld.txt");
我正在使用此代码尝试。我尝试了两种方法来做到这一点。首先,当使用File
我收到FileNotFoundException
,当使用AssetManager getAssets()
方法时无法识别。
这里有什么解决办法吗?
【问题讨论】:
【参考方案1】:这是我在缓冲阅读扩展/修改以满足您的需求的活动中所做的
BufferedReader reader = null;
try
reader = new BufferedReader(
new InputStreamReader(getAssets().open("filename.txt")));
// do reading, usually loop until end of file reading
String mLine;
while ((mLine = reader.readLine()) != null)
//process line
...
catch (IOException e)
//log the exception
finally
if (reader != null)
try
reader.close();
catch (IOException e)
//log the exception
编辑:如果您的问题是关于如何在活动之外进行操作,我的回答可能毫无用处。如果您的问题只是如何从资产中读取文件,那么答案就在上面。
更新:
要打开指定类型的文件,只需在 InputStreamReader 调用中添加类型,如下所示。
BufferedReader reader = null;
try
reader = new BufferedReader(
new InputStreamReader(getAssets().open("filename.txt"), "UTF-8"));
// do reading, usually loop until end of file reading
String mLine;
while ((mLine = reader.readLine()) != null)
//process line
...
catch (IOException e)
//log the exception
finally
if (reader != null)
try
reader.close();
catch (IOException e)
//log the exception
编辑
正如@Stan 在评论中所说,我给出的代码不是总结行。 mLine
每次通过都会被替换。这就是我写//process line
的原因。我假设该文件包含某种数据(即联系人列表),并且每一行都应该单独处理。
如果您只是想在不进行任何处理的情况下加载文件,则必须在每次通过时使用 StringBuilder()
总结 mLine
并附加每个通过。
另一个编辑
根据@Vincent 的评论,我添加了finally
块。
另请注意,在 Java 7 及更高版本中,您可以使用 try-with-resources
来使用最新 Java 的 AutoCloseable
和 Closeable
功能。
上下文
@LunarWatcher 在评论中指出getAssets()
是class
中的context
。因此,如果您在 activity
之外调用它,则需要引用它并将上下文实例传递给活动。
ContextInstance.getAssets();
@Maneesh 的回答对此进行了解释。因此,如果这对您有用,请支持他的回答,因为是他指出了这一点。
【讨论】:
@Stan,然后在 cmets 中写下它,让作者决定是否要更新它。编辑是为了提高清晰度,而不是改变含义。代码修订应始终首先作为 cmets 发布。 您的代码不保证及时关闭流并释放资源。我建议你使用finally reader.close();
。
我认为指出上面的代码在 ADT 中显示错误是有用的 - “reader.close();”行需要放在另一个 try-catch 块中。检查此线程:***.com/questions/8981589/… :)
getAssets 是 Context 中的一个类,因此要在活动之外使用,需要调用 Context。所以在活动之外,它会像context.getAssets(.....)
根据您的更新(感谢您添加了顺便说一句),在静态字段中包含上下文是内存泄漏。应谨慎使用并妥善清理。否则最终会导致内存泄漏,这可能会对应用产生重大影响。【参考方案2】:
getAssets()
仅适用于在活动中在您必须使用Context
的其他任何类中。
为 Utils 创建一个 构造函数 类将活动(丑陋的方式)或应用程序上下文的引用作为参数传递给它。在 Utils 类中使用 getAsset()。
【讨论】:
它适用于任何属于 Context 子类的东西,而 Activity 就是其中之一。 刚刚注意到我写了Context
。
@user370305 你知道吗,如何将 InputStream 转换为 FileInputStream?
@user370305 这有多丑?
在不考虑后果的情况下传递 UI 对象通常是一种不好的做法。如果您不小心,可能会导致内存泄漏或尝试使用死上下文。很好的阅读主题:android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570【参考方案3】:
迟到总比没有好。
在某些情况下,我难以逐行读取文件。 下面的方法是我目前找到的最好的方法,我推荐它。
用法:String yourData = LoadData("YourDataFile.txt");
假设 YourDataFile.txt 位于 assets/
中 public String LoadData(String inFile)
String tContents = "";
try
InputStream stream = getAssets().open(inFile);
int size = stream.available();
byte[] buffer = new byte[size];
stream.read(buffer);
stream.close();
tContents = new String(buffer);
catch (IOException e)
// Handle exceptions here
return tContents;
【讨论】:
我的返回字符串是 android.content.res.AssetManager$AssetInputStream@4195dfa0 .. 这里一样,res.AssetManager$AssetInputStream@.... 有什么特殊原因返回这个吗? 你双重分配内存 - 首先是缓冲区,然后是字符串。不适用于更大的文件。 为缓冲区分配大小的完美方式stream.available()
。【参考方案4】:
public String ReadFromfile(String fileName, Context context)
StringBuilder returnString = new StringBuilder();
InputStream fIn = null;
InputStreamReader isr = null;
BufferedReader input = null;
try
fIn = context.getResources().getAssets()
.open(fileName, Context.MODE_WORLD_READABLE);
isr = new InputStreamReader(fIn);
input = new BufferedReader(isr);
String line = "";
while ((line = input.readLine()) != null)
returnString.append(line);
catch (Exception e)
e.getMessage();
finally
try
if (isr != null)
isr.close();
if (fIn != null)
fIn.close();
if (input != null)
input.close();
catch (Exception e2)
e2.getMessage();
return returnString.toString();
【讨论】:
您会认为如果关闭 BufferedReader,那么它也必须自动关闭 InputStreanReader 和 InputStream。因为你没有为那些创建句柄,例如input = new BufferedReader(new InputStreamReader(fIn));
.
我建议创建单独的 try/catch 块以在最后关闭所有资源;而不是将它们全部归为一个 - 因为如果先前尝试关闭另一个资源的尝试引发异常,它可能会使其他资源处于未关闭状态。【参考方案5】:
kotlin 的单线解决方案:
fun readFileText(fileName: String): String
return assets.open(fileName).bufferedReader().use it.readText()
你也可以把它作为扩展函数everyWhere使用
fun Context.readTextFromAsset(fileName : String) : String
return assets.open(fileName).bufferedReader().use
it.readText()
只需在任何上下文类中调用
context.readTextFromAsset("my file name")
【讨论】:
【参考方案6】:AssetManager assetManager = getAssets();
InputStream inputStream = null;
try
inputStream = assetManager.open("helloworld.txt");
catch (IOException e)
Log.e("message: ",e.getMessage());
【讨论】:
【参考方案7】:getAssets()
方法将在您在 Activity 类中调用时起作用。
如果你在非Activity类中调用这个方法,那么你需要从Activity类传递的Context中调用这个方法。所以下面是您可以访问该方法的行。
ContextInstance.getAssets();
ContextInstance
可以作为 Activity 类的 this 传递。
【讨论】:
【参考方案8】:读取和写入文件一直很冗长且容易出错。避免使用这些答案,而是使用Okio:
public void readLines(File file) throws IOException
try (BufferedSource source = Okio.buffer(Okio.source(file)))
for (String line; (line = source.readUtf8Line()) != null; )
if (line.contains("square"))
System.out.println(line);
【讨论】:
你知道为什么这看起来更美观更短吗?好吧,因为您在这里至少省略了一半的代码。省略部分: 1)IOException
的 try/catch 块 2) 在抛出异常的情况下关闭流 3) 此代码读取单行,而不是整个文件。在性能方面,这个库绝对是同类中的一员,这一点毫无疑问。现在,告诉我是否仍应避免“这些答案”并仅为读取文件而实施 Okio?答案是否定的,除非它已经是您应用的一部分。【参考方案9】:
这里是读取资产中文件的方法:
/**
* Reads the text of an asset. Should not be run on the UI thread.
*
* @param mgr
* The @link AssetManager obtained via @link Context#getAssets()
* @param path
* The path to the asset.
* @return The plain text of the asset
*/
public static String readAsset(AssetManager mgr, String path)
String contents = "";
InputStream is = null;
BufferedReader reader = null;
try
is = mgr.open(path);
reader = new BufferedReader(new InputStreamReader(is));
contents = reader.readLine();
String line = null;
while ((line = reader.readLine()) != null)
contents += '\n' + line;
catch (final Exception e)
e.printStackTrace();
finally
if (is != null)
try
is.close();
catch (IOException ignored)
if (reader != null)
try
reader.close();
catch (IOException ignored)
return contents;
【讨论】:
这是一个很好的答案,但使用字符串连接是不好的方法。考虑改用 StringBuilder。 StringBuilder contentBuilder = new StringBuilder(); while((line = reader.readLine()) != null) builder.append("\n").append(line);最后,您可以通过以下方式创建新的 String 对象: content = contentBuilder.toString();【参考方案10】:您可以从文件中加载内容。考虑文件存在于资产文件夹中。
public static InputStream loadInputStreamFromAssetFile(Context context, String fileName)
AssetManager am = context.getAssets();
try
InputStream is = am.open(fileName);
return is;
catch (IOException e)
e.printStackTrace();
return null;
public static String loadContentFromFile(Context context, String path)
String content = null;
try
InputStream is = loadInputStreamFromAssetFile(context, path);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
content = new String(buffer, "UTF-8");
catch (IOException ex)
ex.printStackTrace();
return null;
return content;
现在你可以通过如下调用函数来获取内容
String json= FileUtil.loadContentFromFile(context, "data.json");
考虑到data.json存储在Application\app\src\main\assets\data.json
【讨论】:
【参考方案11】:在 MainActivity.java 中
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvView = (TextView) findViewById(R.id.tvView);
AssetsReader assetsReader = new AssetsReader(this);
if(assetsReader.getTxtFile(your_file_title)) != null)
tvView.setText(assetsReader.getTxtFile(your_file_title)));
此外,您可以创建单独的类来完成所有工作
public class AssetsReader implements Readable
private static final String TAG = "AssetsReader";
private AssetManager mAssetManager;
private Activity mActivity;
public AssetsReader(Activity activity)
this.mActivity = activity;
mAssetManager = mActivity.getAssets();
@Override
public String getTxtFile(String fileName)
BufferedReader reader = null;
InputStream inputStream = null;
StringBuilder builder = new StringBuilder();
try
inputStream = mAssetManager.open(fileName);
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while((line = reader.readLine()) != null)
Log.i(TAG, line);
builder.append(line);
builder.append("\n");
catch (IOException ioe)
ioe.printStackTrace();
finally
if(inputStream != null)
try
inputStream.close();
catch (IOException ioe)
ioe.printStackTrace();
if(reader != null)
try
reader.close();
catch (IOException ioe)
ioe.printStackTrace();
Log.i(TAG, "builder.toString(): " + builder.toString());
return builder.toString();
我认为最好是创建一个界面,但这不是必需的
public interface Readable
/**
* Reads txt file from assets
* @param fileName
* @return string
*/
String getTxtFile(String fileName);
【讨论】:
【参考方案12】:如果您使用 Activity 以外的任何其他类,您可能想要这样做,
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( YourApplication.getInstance().getAssets().open("text.txt"), "UTF-8"));
【讨论】:
【参考方案13】:使用 Kotlin,您可以执行以下操作从 Android 中的资产中读取文件:
try
val inputStream:InputStream = assets.open("helloworld.txt")
val inputString = inputStream.bufferedReader().useit.readText()
Log.d(TAG,inputString)
catch (e:Exception)
Log.d(TAG, e.toString())
【讨论】:
【参考方案14】:可能为时已晚,但为了寻找桃色答案的其他人:
public static String loadAssetFile(Context context, String fileName)
try
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(context.getAssets().open(fileName)));
StringBuilder out= new StringBuilder();
String eachline = bufferedReader.readLine();
while (eachline != null)
out.append(eachline);
eachline = bufferedReader.readLine();
return out.toString();
catch (IOException e)
Log.e("Load Asset File",e.toString());
return null;
【讨论】:
【参考方案15】:这是一种在没有Context
、Activity
、Fragment
或Application
的情况下为assets
文件夹中的文件获取InputStream
的方法。如何从 InputStream
获取数据取决于您。在这里的其他答案中有很多建议。
科特林
val inputStream = ClassLoader::class.java.classLoader?.getResourceAsStream("assets/your_file.ext")
Java
InputStream inputStream = ClassLoader.class.getClassLoader().getResourceAsStream("assets/your_file.ext");
如果自定义 ClassLoader
在游戏中,所有赌注都将取消。
【讨论】:
【参考方案16】:cityfile.txt
public void getCityStateFromLocal()
AssetManager am = getAssets();
InputStream inputStream = null;
try
inputStream = am.open("city_state.txt");
catch (IOException e)
e.printStackTrace();
ObjectMapper mapper = new ObjectMapper();
Map<String, String[]> map = new HashMap<String, String[]>();
try
map = mapper.readValue(getStringFromInputStream(inputStream), new TypeReference<Map<String, String[]>>()
);
catch (IOException e)
e.printStackTrace();
ConstantValues.arrayListStateName.clear();
ConstantValues.arrayListCityByState.clear();
if (map.size() > 0)
for (Map.Entry<String, String[]> e : map.entrySet())
CityByState cityByState = new CityByState();
String key = e.getKey();
String[] value = e.getValue();
ArrayList<String> s = new ArrayList<String>(Arrays.asList(value));
ConstantValues.arrayListStateName.add(key);
s.add(0,"Select City");
cityByState.addValue(s);
ConstantValues.arrayListCityByState.add(cityByState);
ConstantValues.arrayListStateName.add(0,"Select States");
// Convert InputStream to String
public String getStringFromInputStream(InputStream is)
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null)
sb.append(line);
catch (IOException e)
e.printStackTrace();
finally
if (br != null)
try
br.close();
catch (IOException e)
e.printStackTrace();
return sb + "";
【讨论】:
链接现在返回File no longer available That file has now been permanently removed and cannot be recovered
【参考方案17】:
Scanner 类可以简化这一点。
StringBuilder sb=new StringBuilder();
Scanner scanner=null;
try
scanner=new Scanner(getAssets().open("text.txt"));
while(scanner.hasNextLine())
sb.append(scanner.nextLine());
sb.append('\n');
catch (IOException e)
e.printStackTrace();
finally
if(scanner!=null)tryscanner.close();catch (Exception e)
mTextView.setText(sb.toString());
【讨论】:
你可以合并这两行 sb.append(scanner.nextLine()); sb.append('\n');到 sb.appendln(scanner.nextLine()); 没有这个功能 @SinceKotlin("1.4") 添加了appendLine函数,弃用了appendln【参考方案18】:@HpTerm回答Kotlin版本:
private fun getDataFromAssets(activity: Activity): String
var bufferedReader: BufferedReader? = null
var data = ""
try
bufferedReader = BufferedReader(
InputStreamReader(
activity?.assets?.open("Your_FILE.html"),
"UTF-8"
)
) //use assets? directly if inside the activity
var mLine:String? = bufferedReader.readLine()
while (mLine != null)
data+= mLine
mLine=bufferedReader.readLine()
catch (e: Exception)
e.printStackTrace()
finally
try
bufferedReader?.close()
catch (e: Exception)
e.printStackTrace()
return data
【讨论】:
目前这会将 null 添加到字符串中。需要更改:var mLine:String
应该是 var mLine:String?
var data: String?
应该是 var data = ""
返回类型应该是 String
它还会去除行尾。 :(以上是关于从资产中读取文件的主要内容,如果未能解决你的问题,请参考以下文章
从资产目录读取文件抛出 FileNotFoundException