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"));
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章