Java 如何在android应用程序上读取大型Base64文件(150MB)?

Java 如何在android应用程序上读取大型Base64文件(150MB)?,java,android,Java,Android,我正在尝试在android应用程序上读取大小为(~150MB)的大型base64文本文件 该文件包含JSON字符串,我需要将其解码并转换为JSON对象,然后在应用程序中使用它。问题是,在尝试读取此数据时,内存中出现异常 该应用程序需要脱机工作,因此我需要下载完整数据 代码如下: String localPath = getApplicationContext().getFilesDir().getPath().toString() ; String key = "dataFile

我正在尝试在android应用程序上读取大小为
(~150MB)
的大型
base64
文本文件

该文件包含JSON字符串,我需要将其解码并转换为JSON对象,然后在应用程序中使用它。问题是,在尝试读取此数据时,内存中出现异常

该应用程序需要脱机工作,因此我需要下载完整数据

代码如下:

    String localPath = getApplicationContext().getFilesDir().getPath().toString() ;
    String key = "dataFile.txt" ;

    StringBuilder text = new StringBuilder();
    File file=new File(localPath+"/"+ key);

    byte fileContent[] = new byte[3000];

    try ( FileInputStream fin = new FileInputStream(file)) {
        while(fin.read(fileContent) >= 0) {
            byte[] data = Base64.decode(fileContent, Base64.DEFAULT);
            try {
                text.append(new String(data, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        obj = new JSONObject(text.toString());
    }catch (Exception e){
        e.printStackTrace();
    }

如何读取此类文件?

您试图通过读取文件、迭代文件并将每一行附加到
文本中,将整个文件读取到
文本对象中。您可以使用
文本
对象创建
JSONObject
,该对象仅在最后一步中对应用程序有用

在这里,当代码到达行
obj=newJSONObject(text.toString())时
您已经用几乎与输入文件大小相同的大小填充了堆,因为这个完整的文件以
test
对象的形式存在于内存中。然后将该
text
对象设置为
JSONObject

您可以采取以下措施来消除此问题:

  • 使用
    BufferedReader
    分块读取文件(可选)。使用
    read()
    可能有点慢,最好有一个缓冲区
  • 迭代该文件,并将条目成批地放入
    1000
    10000
    text
    对象中
  • text
    中准备
    JSONObject
    并将其附加到
    obj
  • 在处理下一批之前,清除
    文本
    对象,然后重复整个过程
  • 通过这样做,您只读取了内存中文件的一小部分,并且
    text
    对象充当缓冲区,只消耗了少量内存

    以下是示例代码段:

    int counter = 0;
    String temp = null;
    final int BATCH_SIZE = 1000;
    try (BufferedReader br = new BufferedReader(new FileReader(path)) {
    
        while ((temp = br.readLine()) != null) {
            text.append(temp);
            ++counter;
    
            /* Process In Batches */
            if(counter % BATCH_SIZE == 0) {
                /* Prepare & Append JSON Objects */
                obj = prepareAppendJSON(text.toString(), obj);
                /* Clear text */
                text.setLength(0);
            }
        }
    
        /* Last Iteration */
        obj = prepareAppendJSON(text, obj);
        text = new StringBuilder();
    
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    

    您唯一的选择是使用
    JSON流媒体
    ,并对您感兴趣的事件做出反应

    import org.codehaus.jackson.*;
    
    .....
    
    JsonParser parser = new JsonFactory().createJsonParser( yourFileInputStream );
    parser.configure( Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true );
    parser.configure( Feature.ALLOW_SINGLE_QUOTES, true );
    // add more features
    
    for( JsonToken token = parser.nextToken(); null != token; token = parser.nextToken() ){
      switch( token ){
        case FIELD_NAME:
          doStuffWithName();
          break;
    
        case START_OBJECT:
          doObjectStart();
          break;
    
        case END_OBJECT:
          processObject();
          break;
    
        // other events
      }
    }
    
    我在4.0设备上使用了上述代码,JSON文件大小为10 MB


    另外,你需要先解码你原来的Base64文件。不确定是否可以在
    java.io.Stream
    中动态执行。在最坏的情况下,将Base64文件解压成一个普通的json,然后使用上面的json流代码

    你首先解雇那些认为Base64编码的json是个好主意的人,然后改造服务器,将常规json交给你。生成的~110MB JSON字符串仍然太大,无法使用
    JSONObject
    进行解析。如果您只需要一小部分数据,请使用流式JSON解析器(Gson、Jackson等)。谢谢!但是什么是prepareAppendJSON方法呢?它是一个自定义对象,您必须编写它来准备字符串中的
    JSONObject
    ,然后将其附加到给定的
    JSONObject