java sax动态生成xml,大量数据时、防止内存储器溢出
java sax动态生成xml,大量数据时、防止内存溢出
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import com.sbdcpn.upload.FtpClient; import com.sbdcpn.utils.Log; import com.sbdcpn.xmlparse.pagecfg.PageCfgXMLUtil; public class BigDataWriteXmlBo { private final int records = 1000; /** * 将数据保存到xml上 * @throws ParserConfigurationException * @throws IOException * @throws TransformerException * @throws SAXException * @throws InterruptedException */ @SuppressWarnings({ "unchecked", "rawtypes" }) public void generateXML() throws IOException, TransformerException, SAXException, InterruptedException{ SAXTransformerFactory fac = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); TransformerHandler handler = fac.newTransformerHandler(); Transformer transformer = handler.getTransformer(); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");// // 设置输出采用的编码方式 transformer.setOutputProperty(OutputKeys.INDENT, "yes");// 是否自动添加额外的空白 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");// 是否忽略xml声明 //文件名 :前七位SWPM001为电文号+14位日期(年月日时分秒) StringBuffer fileName = new StringBuffer("SWPM001_"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); fileName.append(sdf.format(new Date())).append(".xml"); FileOutputStream fos = new FileOutputStream(fileName.toString()); Result resultxml = new StreamResult(fos); handler.setResult(resultxml); //Message标签的属性 AttributesImpl msgAtt = new AttributesImpl(); msgAtt.addAttribute("", "", "MsgID", "", "SWPM001"); msgAtt.addAttribute("", "", "ResourceID", "", "SW"); handler.startDocument(); handler.startElement("", "", "Message", msgAtt); //空属性 AttributesImpl fieldAtt = new AttributesImpl(); //取得总记录数,进行分页处理 long count = queryAllRows(); long page = count / records; if (count % records != 0) { page = page + 1; } String four = "\n "; String eight = "\n "; //开始行号,结束行号 long start = 1, end = records; //根据页数进行循环 for (long j = 1; j <= page; j++) { // 分页取得目录数据 List<Map> data = this.queryStockInventory(start, end); //按行循环一页中的数据 for (int i = 0; i < data.size(); i++) { handler.characters(four.toCharArray(), 0, four.length());//行缩进 Map<String, String> rec = data.get(i); //行结点属性 AttributesImpl dataRowAtt = new AttributesImpl(); dataRowAtt.addAttribute("", "", "id", "", String.valueOf(start - 1 + i)); // 行结点 handler.startElement("", "", "DataRow", dataRowAtt); rec.remove("row_num"); Iterator it = rec.entrySet().iterator(); //按列循环生成数据结点 while (it.hasNext()) { handler.characters(eight.toCharArray(), 0, eight.length());// 列缩进 Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next(); String key = entry.getKey(); String value = entry.getValue(); // 用字段名作为标签名,对应的数据作为内容 handler.startElement("", "", key, fieldAtt); handler.characters(value.toCharArray(), 0, value.length()); handler.endElement("", "", key); } handler.characters(four.toCharArray(), 0, four.length());//行缩进 handler.endElement("", "", "DataRow"); } start = end + 1; end = end + records; handler.endDocument();// 文档结束,同步到磁盘 handler.startDocument(); } handler.endElement("", "", "Message"); handler.endDocument(); fos.close();//不关闭的话,后面删除不了文件 uploadFile(fileName.toString());// 上传文件至ftp } /** * 把生成出来的文件,上传到ftp;上传失败后,1分钟后再次尝试上传,连续三次不成功便停止 * @param fileName 文件名 * @param filePath 路径 * @throws InterruptedException */ private void uploadFile(String fileName) throws InterruptedException { String[] path = PageCfgXMLUtil.getInstance().getPageConstByKey("stockFtpXmlPath").split(" "); int reSend = 1; //上传失败时,1分钟后再次尝试 while (reSend <= 3) { FtpClient ftp = new FtpClient(); ftp.Connect(path[0], Integer.parseInt(path[1]));// ip与端口 ftp.Login(path[3], path[4]);// 用户名与密码 ftp.SetCurDir(path[2]);// 目录 boolean isUpload = ftp.PutFile(fileName, fileName); ftp.DisConnect(); if (isUpload) { _log.showLog(fileName + "成功上传到FTP服务器上!"); break; } else { _log.showLog(fileName + "尝试" + reSend + "次后,上传到FTP服务器失败!"); reSend++; Thread.sleep(60000); } } File file = new File(fileName); String flag = file.delete() ? "成功!" : "失败!"; _log.showLog("删除临时文件:" + fileName + flag); } /** * 分页查询,示例查询,假设数据有十万条 * @return */ @SuppressWarnings("rawtypes") private List queryStockInventory(long start, long end) { StringBuffer insertInto = new StringBuffer(); insertInto.append(" SELECT") .append(" tmp_stock_inv.*") .append(" FROM(") .append(" SELECT *,") .append("rownum row_num") .append(" FROM table") .append(" WHERE rownum <=").append(end) .append(") tmp_stock_inv") .append(" WHERE") .append(" tmp_stock_inv.row_num >=").append(start); _log.showLog("查询:" + insertInto.toString()); return _dao.query(insertInto.toString()); } /** * 取得总记录数 * @return */ @SuppressWarnings("unchecked") private int queryAllRows() { StringBuffer insertInto = new StringBuffer(); insertInto.append("SELECT count(*) rows_count FROM stock_inventory WHERE stock_qty > 0"); _log.showLog("查询总记录数:" + insertInto.toString()); Map<String,String> rs = (Map<String,String>)_dao.queryOneRow(insertInto.toString()); return Integer.parseInt(rs.get("rows_count")); } }