需求描述:
最近在写一个定时任务,发送多次请求到接口,接口返回报文写入到一个文件中,文件要求格式第一行为总数。这个总数只能在最后的时候才能知道,
这就相当于提出了一个要求:在文件的第一行添加内容,以前的内容整体向下偏移一行。
遇到的问题:
我开始做的方法是,在代码中 new StringBuffer ,等全部报文返回后,把返回的报文先全部保存到buffer中,用PrintWriter写入总数到文件,再将返回报文写入。可在实际代码运行中,由于每次返回的报文都存入到buffer中,返回的报文对象被buffer对象引用,没有释放掉,所以占用内存很大。折腾了半天不可行。只能换一种思路了。这个文件大小是50多M,内存几百兆没了。
那既然一次性保存到buffer中不行,那就返回一次报文就保存到本地临时文件中tmpFile,最后在另一个文件dinsFile中先写入总数,从tmpFile没读取一行,就写入到dinsFile。一开始没想到用Scammer这个类,从网上看其他网友的博文才发现正适合,还是很菜,多多学习。
这样占用内存的问题就解决了。下面上代码:
public class QueryBondBalTask extends BaseService{
private String url;
private Logger logger = Logger.getLogger(QueryBondBalTask.class);
public void setUrl(String url) {
this.url = url;
}
public void getBondBalToText() {
ICstpCustodianConfigDao cstpCustodianConfigDao = (ICstpCustodianConfigDao) context.getBean("ICstpCustodianConfigDao");
List<String> list = cstpCustodianConfigDao.selectCustodianAccount();
// 创建输出临时文件
String date = DateTimeClass.getCurDate();
String name = "tmp_bond_subject_csbs_" + date + "_.txt";
String tmpPath = FppTradeConfig.ReadStringFromConfig("QueryBondBalTask.tmpPath");
File tmpFile = new File(tmpPath + name);
//中债登的接口包
DClient dClient = new DClient(url);
SAXReader saxReader = new SAXReader();
long sum = 0;
Reader reader = null;
PrintWriter pw = null;
try {
pw = new PrintWriter(tmpFile);
for (String bondId : list) {
// 模拟请求报文
String requestXml = createXml(bondId);
// 调用接口查询
String backMsg = dClient.sendMsg(requestXml);
if (backMsg == null || "" == backMsg) {
logger.error("返回报文异常", new Exception());
}
//解析返回backMsg,生成临时文件
InputStream input1 = new ByteArrayInputStream(backMsg.getBytes());
reader = new InputStreamReader(input1);
Document document = saxReader.read(reader);
Element root = document.getRootElement();
// 获取债券账号
Node accountNode = root.selectSingleNode("//Id");
String account = accountNode.getText();
// 余额条数
List acctLdgList = root.selectNodes("//AcctLdg");
int size = acctLdgList.size();
// 获取所有<Bd>标签
List<Element> bdList = root.selectNodes("//Bd");
for (Element bond : bdList) {
Node bdidNode = bond.selectSingleNode("BdId");
String bdid = bdidNode.getText();
// 从当前节点下获取<AcctLdg>
List<Element> acctLdglList = bond.selectNodes("SummryStmt/AcctLdg");
for (Element acctLdg : acctLdglList) {
Node ldgTpnNode = acctLdg.selectSingleNode("LdgTp");
String ldgTp = ldgTpnNode.getText();
Node balNode = acctLdg.selectSingleNode("Bal");
String bal = balNode.getText();
String record = account + "|" + bdid + "|" + ldgTp + "|" + bal;
pw.println(record);
}
}
pw.flush();
sum = sum + size;
}
//将总数写入文件
WriteSum(sum,tmpFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
logger.error("中债登接口调用异常", e);
} catch (DocumentException e) {
e.printStackTrace();
logger.error("", e);
} catch (Exception e) {
e.printStackTrace();
logger.error("返回报文异常", e);
} finally{
if (pw != null) {
pw.close();
}
tmpFile.delete();
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String createXml(String bondId) {
String appPath = FppCommMethod.getAPP_HOME();
String path=appPath + "/config/request.xml";
File file = new File(path);
SAXReader saxReader = new SAXReader();
Document document = null;
try {
document = saxReader.read(file);
} catch (DocumentException e) {
e.printStackTrace();
logger.error("", e);
}
Element root = document.getRootElement();
Node txFlowIdNode = root.selectSingleNode("//TxFlowId");
String txFlowId = SequenceCreater.getReconTxFlowID();
txFlowIdNode.setText(txFlowId);
Node creDtNode = root.selectSingleNode("//CreDtTm");
String CreDtTmDate = DateTimeClass.getCurFormatTime();
creDtNode.setText(CreDtTmDate);
Node startNode = root.selectSingleNode("//StartDt");
String startDate = DateTimeClass.getCurFormatDate();
startNode.setText(startDate);
Node endNode = root.selectSingleNode("//EndDt");
String endDate = DateTimeClass.getCurFormatDate();
endNode.setText(endDate);
Node idNode = root.selectSingleNode("//Id");
idNode.setText(bondId);
String requestXml = document.asXML();
return requestXml;
}
//读取文件,将总数写入
private void WriteSum(long sum, File tmpFile) {
// 最终文件
String date = DateTimeClass.getCurDate();
String name = "bond_subject_csbs_" + date + ".txt";
String destPath = FppTradeConfig.ReadStringFromConfig("QueryBondBalTask.destPath");
File file = new File(destPath + name);
PrintWriter pw = null;
Scanner scanner = null;
InputStream input = null;
try {
//输出到最终文件
pw = new PrintWriter(file);
pw.println(sum);
//读取临时文件
input = new FileInputStream(tmpFile);
scanner = new Scanner(input);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
pw.println(line);
}
pw.print("END");
pw.flush();
} catch (FileNotFoundException e) {
logger.error("",e);
} finally{
if (scanner != null) {
scanner.close();
}
if (pw != null) {
pw.close();
}
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}