java - 使用 jQuery 或 Java 制作大文件的最佳方法
问题描述
我正在用 jQuery 和 Java 开发一个网络应用程序。我的任务是用一些数据库记录制作报告。报告必须能够以 csv、xls 和 txt 格式下载。文件的记录数是可变的,但有些时候太大了,比如一千万条记录。
我有两个问题:
- 第一:制作大文件的最佳选择是Java还是jQuery?
- 第二:你能给我一个实现的例子吗?
我目前在jQuery中实现了csv格式的报表,效果很好,细节是当报表超过800000条记录时,浏览器内存结束,报错结束。你知道一些解决方法吗?
这是代码:
$("#btnSaveReporte").on(
'click',
function(event) {
getValuesSelected();
var valiFec = validarFechasEnUso();
if (validarFechasEnUso()) {
if (validarCampos()){
// get data report
$.ajax({
type : "POST",
url : "/VentasB/api/getDataReport",
data : {
fechaIni : fechaIni,
fechaFin : fechaFin,
orgVentas : Object.keys(orgVentas).join(',').replace(/'/g, ""),
canalDist : Object.keys(canalDist).join(','),
//canalDist : "'10','11','12'",
sector : Object.keys(sector).join(',').replace(/'/g, ""),
ofiVentas : $.map(ofiVentas, function(obj) { return "'" + obj.value + "'" }).join(','),
},
success : function(result) {
console.log(result);
if(result.data.length > 0){
// CSV
var fileName = "Reporte_Ventas_" + fechaIni
+ "_to_" + fechaFin + ".csv";
exportDataToCSV(result.data, fileName,
"#reportFile");
// trigger de click para descargar automaticamente el reporte
$("#reportFile")[0].click();
}else{
Swal.fire({
icon : 'info',
title : 'Sin resultados',
text : 'no se econtró ningún registro que cumpla con los parametros de busqueda.'
})
}
}
});
}
} else {
// swal error
}
});
// ******************** funcion para descargar csv *********************
function exportDataToCSV(data, title, btnContainer) {
var csv = ""
for (var g = 0; g < data.length; g++) {
// for(var g=0; g < 100; g++){
// console.log("entro data")
// console.log(data[g])
if (g == 0) {
csv += "bill_stmnt_id, distributor_id, bill_type_cd, bill_stmnt_base_id, eff_dt, eff_tm, bill_distrib_channel_cd,"
+ "total_charge_amt, total_tax_amt, subtotal_amt, discounts, bill_equipment_deposit, price, perc_fin, amt_fin,"
+ "bill_rfc_ini, bill_customer_cd, bill_shop_cd, bill_shop_name,bill_shop_id, bill_org_name, bill_address,"
+ "bill_move_type_cd, bill_payment_condition_cd, region_id, bill_customer_group_cd, bill_customer_group_desc,"
+ "bill_user_id, bill_sale_force_desc, bill_sale_reason_cd, bill_rfc_end, bill_source_type_cd";
csv += "\n";
}
csv += '"' + data[g].bill_stmnt_id + '",';
csv += '"' + data[g].distributor_id + '",';
csv += '"' + data[g].bill_type_cd + '",';
csv += '"' + data[g].bill_stmnt_base_id + '",';
csv += '"' + data[g].eff_dt + '",';
csv += '"' + data[g].eff_tm + '",';
csv += '"' + data[g].bill_distrib_channel_cd + '",';
csv += '"' + data[g].total_charge_amt + '",';
csv += '"' + data[g].total_tax_amt + '",';
csv += '"' + data[g].subtotal_amt + '",';
csv += '"' + data[g].discounts + '",';
csv += '"' + data[g].bill_equipment_deposit + '",';
csv += '"' + data[g].price + '",';
csv += '"' + data[g].perc_fin + '",';
csv += '"' + data[g].amt_fin + '",';
csv += '"' + data[g].bill_rfc_ini + '",';
csv += '"' + data[g].bill_customer_cd + '",';
csv += '"' + data[g].bill_shop_cd + '",';
csv += '"' + data[g].bill_shop_name + '",';
csv += '"' + data[g].bill_shop_id + '",';
csv += '"' + data[g].bill_org_name + '",';
csv += '"' + data[g].bill_address + '",';
csv += '"' + data[g].bill_move_type_cd + '",';
csv += '"' + data[g].bill_payment_condition_cd + '",';
csv += '"' + data[g].region_id + '",';
csv += '"' + data[g].bill_customer_group_cd + '",';
csv += '"' + data[g].bill_customer_group_desc + '",';
csv += '"' + data[g].bill_user_id + '",';
csv += '"' + data[g].bill_sale_force_desc + '",';
csv += '"' + data[g].bill_sale_reason_cd + '",';
csv += '"' + data[g].bill_rfc_end + '",';
csv += '"' + data[g].bill_source_type_cd + '",';
// csv += "hola" + "," ;
csv += "\n";
}
// Deliberate 'false', see comment below
if (false && window.navigator.msSaveBlob) {
console.log("entro 1")
var blob = new Blob([ decodeURIComponent(csv) ], {
type : 'text/csv;charset=utf8'
});
// Crashes in IE 10, IE 11 and Microsoft Edge
// See MS Edge Issue #10396033
// Hence, the deliberate 'false'
// This is here just for completeness
// Remove the 'false' at your own risk
window.navigator.msSaveBlob(blob, title);
} else if (window.Blob && window.URL) {
console.log("entro 2")
// HTML5 Blob
var blob = new Blob([ csv ], {
type : 'text/csv;charset=utf-8'
});
var csvUrl = URL.createObjectURL(blob);
$(btnContainer).attr({
'download' : title,
'href' : csvUrl
});
} else {
console.log("entro 3")
// Data URI
var csvData = 'data:application/csv;charset=utf-8,'
+ encodeURIComponent(csv);
$(btnContainer).attr({
'download' : title,
'href' : csvData,
'target' : '_blank'
});
}
}
我真的很感谢你的帮助。
解决方案
对于大文件,您不想在内存中构建它然后下载它,因为正如您所见,您将耗尽内存。理想的工作流程是在下载的同时构建它,这样您需要记住的部分就最少了。
Java 方式
由于您正在使用 Java 构建 Web 应用程序,因此您可能使用的是框架,而不是自己实现 HTTP 服务器。您正在使用的库可能支持在请求时提供大型服务,而应用程序的其余部分可以继续工作(流式传输)。最好的方法是使用此功能。
例如,如果您使用的是 Spring MVC,我将实现下载一个大文件,如下所示:
@GetMapping(value="/file/{id}")
public StreamingResponseBody getBigFile(@PathVariable long id) throws IOException {
File f = /* find the file here, for example using id*/;
InputStream in = new BufferedInputStream(new FileInputStream(f));
return new StreamingResponseBody() {
@Override
public void writeTo(OutputStream os) throws IOException {
FileCopyUtils.copy(in, os);
}
};
}
您可以更进一步,仅在写入时才实际写入流;这样,您不必在发送之前将大文件存储在本地。
Javascript 方式
Webworkers + fetch + stream api可能可以帮助您将数据流式传输到文件中,而无需将其存储到内存中。我从来没有尝试过,并且很高兴这似乎是可能的。请注意,并非所有浏览器都支持必要的 Web API
外卖
避免不必要的复制,尽可能使用流式传输而不是缓冲。它节省了大量内存,并且还避免了在需要之前进行工作。
推荐阅读
- r - 迭代地组合两个字符向量
- django - DPI-1047“libclntsh”无法打开共享对象文件:没有这样的文件或目录“
- .net - 如何修复 Visual Studio 2017 中的“无法加载 CLR”?
- powershell - notcontains 不适用于从 AD 组中提取的用户对象
- api - 访问权限不足:GET /me
- jquery - 将 JS 链接添加到 Application.js 文件
- jenkins - 以 5 分钟的速度运行多个作业会阻塞服务器吗?
- java - 为什么谷歌图表在第二次加载时缺少图例文本?
- android - AWS S3 安卓开发工具包 2.11.0
- c - 简单的客户端/服务器出现问题,文件打印错误