目前我正在为Android设备开发web服务,设备可以将json数据上传到服务器(tomcat8上的java webapp),然后将数据保存到db(mysql)中。
我的问题是,数据包含图像,每个上传文件可能增长到大约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"
}
对于填充了所有字段的现有Person和一个Imagedata我想添加一个额外的ImageData而不加载ImageData类型的整个JsonArray,因此输出将是:
{
"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,base 64)到容器?
答案 0 :(得分:0)
在尝试编辑json时,我得到了另一个想法,而不是创建一个大文件进行编辑。
首先,我保存没有图片的数据,只将文件路径放到图像而不是图片中。
因为我只需要JSON上传到网络服务,所以我可以在获取所有正确信息时生成它。
因此,我准备了一个JSON Builder来创建大型文件,该文件使用Jackson依赖于Jackson库将给定数据流式传输到新文件中:
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();
}
}
使用我在问题中输入的Person类并将所有图片添加到此人。使用通过byteArrayFromFile(File)
方法生成的图像本身的字节数组,图片当然保存为Base64。通过读取图像的FileInputStream而不加载位图来节省内存来创建字节数组。即使对于大小约为25MB的图片,应用程序仅使用少于40MB的RAM来生成120MB的JSON文件。字节到Base64的转换由writeBinary(byte[])
的杰克逊库方法JsonGenerator
完成。
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平板电脑仿真器和三星A3 2016(Nougat 7.0)进行测试。