前文
因数据库数据是每日从某一台服务器上的ftp上获取,而经过处理后会产生一些历史数据保留在服务器上,而测试服务在另外一个服务器
需求
在指定时间段内从这些历史数据中查询出来对应的某一条数据,并下载下来;如果使用IO操作的话,会获取所有文件,一次io便利判断是否相等存在,再io,服务器上每天十三个地市,三个月近千,每个文件大小80M左右,这样的话会很慢,且在连接ftp进行IO的过程中,ftp端口占用情况及连接中断各种问题会出现,及网络传输Socket 也可能会中断影响,所以这种方式完全不适合。
另一种想法就是通过命令直接产生需要的文件,再将此文件下载来来,这样在代码中不会一直进行ftp连接及IO操,这样就需要在代码中根据自己的条件产生对应的xshell命令,然后在执行该命令。但是服务器与文件服务器不在同一台上面,因权限,端口开放等问题,最后写个服务放在文件服务器上,并开放某个端口进行调用
这里使用到一些命令 如从某个文件中查询出对应某条数据并写入txt文件cat 20211015北京3.txt |grep 123456 >> 北京_123465.txt
数据格式如图一
如果在指定时间段内挨个文件查询出对应数据的数据呢,这里使用到一个脚本,自行参考
startDate=20210801;endDate=20211005;startSec=`date -d "$startDate" "+%s"`;endSec=`date -d "$endDate" "+%s"`;for((i=$startSec;i<=$endSec;i+=86400)); do yd=`date -d "@$i" "+%Y%m%d"`; cat ${yd}*.txt | grep 123456 >> test.txt ; done
startDate=20210901
endDate=20211005
startSec=`date -d "$startDate" "+%s"`
endSec=`date -d "$endDate" "+%s"`
for((i=$startSec;i<=$endSec;i+=86400))
do
yd=`date -d "@$i" "+%Y%m%d"`
cat ${yd}*.txt | grep * >> *.txt
done
注:在执行此命令的时候,不存的文件会自行过滤,如下图
妈的上传图片上传半小时 ,果断不上传了 贴代码 不说了
package com.jshx.zq.p2p.controller;
import com.alibaba.fastjson.JSON;
import com.jshx.zq.p2p.util.DateUtils;
import com.jshx.zq.p2p.util.ResponseBox;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @author xyg
* @Description 专线号统计导出
* @Date 2021/10/14 9:19
*/
@Slf4j
@RestController
@RequestMapping("/flow")
public class FlowController {
/**
* 根据专线号获取对应的历史流量数据里面的专线号数据
* @param accessNumber
* @param month
* @param city
* @param type 0 互联网 1 组网
* @param request
* @param response
*/
@GetMapping("/downloadAccessNumber")
public ResponseBox downloadAccessNumber(@RequestParam(value = "accessNumber",required = false) String accessNumber,
@RequestParam(value = "month",required = false) String month,
@RequestParam(value = "day",required = false) String day,
@RequestParam(value = "city",required = false) String city,
@RequestParam(value = "type",required = false) String type,
@RequestParam(value = "startTime",required = false) String startTime,
@RequestParam(value = "endTime",required = false) String endTime,
HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info("downloadAccessNumber ======> 据专线号获取对应的历史流量数据里面的专线号数据:accessNumber {}", accessNumber+" month "+month+" city "+city+" type "+type+" startTime "+startTime+" endTime "+endTime);
ResponseBox responseBox = new ResponseBox();
String yesterday = DateUtils.getYesterday();
String[] split = yesterday.split("-");
String year = split[0];
String fileName ="历史流量数据";
StringBuffer commond = new StringBuffer();
List<String> files = new ArrayList<>();
List<String> cpath = new ArrayList<>();
if(month ==null || "".equals(month) || month.equals("null")){
month = split[1];
}
if(day ==null || "".equals(day) || day.equals("day")){
day = split[2];
}else{
if("0".equals(day)) {
day = "*";
}
}
if(type !=null && !"".equals(type) && !!type.equals("type")){
if("1".equals(type)){
type = "组网";
}else{
type ="";
}
}else{
type="";
}
if(city ==null || "".equals(city) || city.equals("city")){
if(!"*".equals(day)){
city = "*";
}
}
commond.append(" "+year);
commond.append(month);
commond.append(day);
commond.append(type);
commond.append(city);
commond.append("3.txt");
if(accessNumber!=null && !"".equals(accessNumber)&&!"null".equals(accessNumber)) {
commond.append(" | grep " + accessNumber + " >> ");
fileName = fileName+".txt";
commond.append(fileName);
cpath.add(commond.toString());
}else{
String com = commond.toString();
fileName = fileName+".tar";
String str = fileName+" "+com;
cpath.add(str);
}
if(startTime!=null && !"".equals(startTime)&&!"null".equals(startTime)
&& endTime!=null && !"".equals(endTime)&&!"null".equals(endTime)) {
fileName = "历史专线数据_"+accessNumber+".txt";
String commods = "startDate="+startTime+";endDate="+endTime+";startSec=`date -d \"$startDate\" \"+%s\"`;endSec=`date -d \"$endDate\" \"+%s\"`;for((i=$startSec;i<=$endSec;i+=86400)); do yd=`date -d \"@$i\" \"+%Y%m%d\"`; cat ${yd}*"+city+"3.txt | grep "+accessNumber+" >> "+fileName+" ; done";
cpath.clear();
cpath.add(commods);
}
files.add(fileName);
ServletOutputStream out = null;
FileInputStream ips = null;
try {
Runtime SYS_RUN = Runtime.getRuntime();
if(startTime!=null && !"".equals(startTime)&&!"null".equals(startTime)
&& endTime!=null && !"".equals(endTime)&&!"null".equals(endTime)) {
log.info("据专线号获取对应的历史流量数据里面的专线号数据 commod "+cpath.get(0));
Process exec = SYS_RUN.exec(new String[]{"sh", "-c", cpath.get(0)});
exec.waitFor();
}else if(accessNumber!=null && !"".equals(accessNumber)&&!"null".equals(accessNumber)) {
log.info("据专线号获取对应的历史流量数据里面的专线号数据 commod "+ "cat "+cpath.get(0));
Process exec = SYS_RUN.exec(new String[]{"sh", "-c", "cat " + cpath.get(0)});
//SYS_RUN.exec 执行该命令时主线程会forck一个子进程,子进程是独立的一个执行实体,会导致主进程继续执行,而子进程的命令尚未执行完毕,文件未生成,
// 进而会出现FileNotFoundException
//waitFor() 阻塞当前主进程正在执行的线程直到子进程返回,主进程才会继续执行
exec.waitFor();
}else{
log.info("据专线号获取对应的历史流量数据里面的专线号数据 commod "+ "tar -zcvf "+cpath.get(0));
Process exec = SYS_RUN.exec(new String[]{"sh", "-c", "tar -zcvf " + cpath.get(0)});
exec.waitFor();
}
String path ="/home/vsftpd/zqftp/lljk/";
String abosPath = path +fileName;
File file = new File(abosPath);
ips = new FileInputStream(file);
response.setContentType("application/*;charset=UTF-8");
fileName = URLEncoder.encode(fileName, "UTF-8");
//为文件重新设置名字,采用数据库内存储的文件名称
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
out = response.getOutputStream();
//读取文件流
int len = 0;
byte[] buffer = new byte[1024 * 10];
while ((len = ips.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.flush();
responseBox.setSuccess(true);
responseBox.setMsg("使用命令获取专线号对应的历史流量成功");
responseBox.setResponseCode(200);
} catch (Exception e) {
log.info("执行命令 "+JSON.toJSONString(cpath.get(0))+" 失败");
responseBox.setSuccess(false);
responseBox.setMsg("使用命令获取专线号对应的历史流量失败");
responseBox.setResponseCode(500);
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
if (ips != null) {
ips.close();
}
removeDir(files);
}
return responseBox;
}
private static void removeDir(List<String> paths) {
Runtime SYS_RUN = Runtime.getRuntime();
for (String path : paths) {
try {
SYS_RUN.exec(new String[]{"sh", "-c", "rm -rf " + path});
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这里需要注意的就是在使用
Process exec = SYS_RUN.exec(new String[]{"sh", "-c", cpath.get(0)}
exec.waitFor();
一定要使用 waitFor 因为
SYS_RUN.exec 执行该命令时主线程会forck一个子进程,子进程是独立的一个执行实体,会导致主进程继续执行,而子进程的命令尚未执行完毕,文件未生成,
进而会出现FileNotFoundException
waitFor() 阻塞当前主进程正在执行的线程直到子进程返回,主进程才会继续执行
最后,不想说了 网不好,图片上传不了