从资产中读取文件

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 的 AutoCloseableCloseable 功能。

上下文

@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】:

这是一种在没有ContextActivityFragmentApplication 的情况下为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 它还会去除行尾。 :(

以上是关于从资产中读取文件的主要内容,如果未能解决你的问题,请参考以下文章

如何显示从资产目录中的文本文件中读取的“®”?

从 Android 上的资产中读取音频文件

从资产目录读取文件抛出 FileNotFoundException

如何使用 Kotlin 从 android 中的资产中读取 json 文件?

如何在 Angular-4 资产中读取 csv 文件

Flutter:如何在不阻塞 UI 的情况下异步地从资产中读取文件