2017-06-19 20 views
0

目前我正在爲android設備的web服務工作,其中設備可以將json數據上傳到服務器(tomcat8上的java webapp),然後將數據保存到數據庫(MySQL的)。在文件JSON編輯沒有加載文件的所有數據

我的問題是,數據包含圖像,並可能增長到每個上傳文件大約100 MB。圖像不得與其他信息分開上傳。

所以我需要把所有的數據放在一個JSON中並上傳它。

我想知道是否有可能用一些json庫訪問json文件而不完全加載它並直接向文件添加更多數據。

一個例子給出這類:

public class Person { 

    private String name; 
    private String surname; 
    private Address address; 
    private List<ImageData> data; 

    public class Address { 
     private String address; 
     private String city; 
     private String state; 
    } 

    public class ImageData { 
     private String id; 
     private String base64; 
    } 
} 

一個人是這樣產生的:

public static String toJson(Person person) { 
     try { 
      JSONObject jsonObject = new JSONObject(); 
      jsonObject.put("name", person.getName()); 
      jsonObject.put("surename", person.getSurname()); 

      JSONObject jsonAdd = new JSONObject(); 
      jsonAdd.put("address", person.getAddress().getAddress()); 
      jsonAdd.put("city", person.getAddress().getCity()); 
      jsonAdd.put("state", person.getAddress().getState()); 

      jsonObject.put("address", jsonAdd); 

      JSONArray jsonArray = new JSONArray(); 

      for(Person.ImageData pn : person.getImageData()) { 
       JSONObject jsonPhone = new JSONObject(); 
       jsonPhone.put("id", pn.getId()); 
       jsonPhone.put("base64", pn.getBase64()); 
       jsonArray.put(jsonPhone); 
      } 

      jsonObject.put("imageData", jsonArray); 

      return jsonObject.toString(); 

     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 

     return null; 
    } 

有了這樣的輸出:

{ 
     "imageData": [ 
     { 
      "base64": "someimage", 
       "id": "11111" 
     } 
    ], 
     "address": { 
     "state": "somewhere", 
       "address": "somewhere, 000", 
       "city": "somewhere city" 
    }, 
     "surname": "sure", 
      "name": "last" 
    } 

要將現有的人與所有字段填充和一個Imagedata我想添加一個額外的ImageData而不加載整個JsonArray類型ImageData所以輸出將是這樣的:

{ 
     "imageData": [ 
     { 
      "base64": "someimage", 
       "id": "11111" 
     }, 
     { 
      "base64": "someimage", 
       "id": "2222" 
     } 
    ], 
     "address": { 
     "state": "somewhere", 
       "address": "somewhere, 000", 
       "city": "somewhere city" 
    }, 
     "surname": "sure", 
      "name": "last" 
    } 

是否可以直接編輯文件而不加載所有內容?像搜索imagedata容器,但不加載內容(id和base64),然後添加一個額外的元素(ID,基地64)到容器?

回答

0

在試圖編輯json時,我得到了另一個想法,而不是創建一個大文件進行編輯。

首先我保存沒有圖片的數據,只把文件路徑放到圖片上而不是圖片上。

因爲我只需要JSON上傳到一個web服務我可以生成它時,所有正確的信息獲得。

所以我準備一個JSON生成器生成的大文件,給定的數據流轉換爲使用這種依賴使用傑克遜庫的新文件:

dependencies { 
... 
    compile 'com.fasterxml.jackson.core:jackson-core:2.7.2' 
... 
} 

而這種進口:

import com.fasterxml.jackson.core.JsonFactory; 
import com.fasterxml.jackson.core.JsonGenerator; 

buildLargeJson(File[], Person)方法中,我首先在public_storage/documents中創建一個新文件,然後創建一個JsonGenerator以通過新文件的FileStream流式傳輸數據。

public static void buildLargeJson(File[] files, Person p) { 
     JsonFactory factory = new JsonFactory(); 
     File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS); 
     File file = new File(dir, "large.json"); 

     try { 
      if (!dir.exists()) 
       dir.mkdirs(); 

      if (!file.exists()) 
       file.createNewFile(); 

      JsonGenerator generator = factory.createGenerator(new FileWriter(file)); 
      generator.writeStartObject(); 
      generator.writeFieldName("name"); 
      generator.writeString(p.getName()); 
      generator.writeFieldName("surname"); 
      generator.writeString(p.getSurname()); 

      if (files != null && files.length > 0) { 
       generator.writeFieldName("imageData"); 
       generator.writeStartArray(); 
       int counter = 1; 
       for (File f : files) { 
        generator.writeStartObject(); 
        generator.writeFieldName("id"); 
        generator.writeNumber(counter++); 
        generator.writeFieldName("base64"); 
        byte[] b = byteArrayFromFile(f); 

        if (b != null) { 
         generator.writeBinary(b); 
        } else { 
         generator.writeString("image not found"); 
        } 

        b = null; 

        generator.writeEndObject(); 
       } 
       generator.writeEndArray(); 
      } 
      generator.writeEndObject(); 
      generator.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

從問題中使用人員類,我把信息和所有圖片添加到人。當然,圖片保存爲Base64,使用通過byteArrayFromFile(File)方法生成的圖片本身的字節數組。字節數組是通過讀取圖像的FileInputStream而創建的,不需要加載位圖來節省內存。即使對於大小爲25MB左右的圖片,應用程序也只能使用不到40MB的RAM來生成120MB的JSON文件。字節到Base64的轉換由Jackson庫JsonGenerator的方法writeBinary(byte[])完成。

private static byte[] byteArrayFromFile(File imageFile) { 
     FileInputStream fis = null; 
     byte[] buffer = new byte[8192]; 
     byte[] b = null; 
     int bytesRead; 

     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     try { 
      fis = new FileInputStream(imageFile); 
      while ((bytesRead = fis.read(buffer)) != -1) { 
       baos.write(buffer, 0, bytesRead); 
      } 

      b = baos.toByteArray(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       baos.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     }  
     return b; 
    } 

使用Android API 19和25標準WXGA Tablet Emulators和Samsung A3 2016(Nougat 7.0)進行測試。