情景:用sqlldr导入数据入库时会产生一些日志,在入库未完成时,日志是大小为0的空文件,能通过日志大小判断是否入库完成
/**
* 等待文件有数据且已写完
* 费时操作 放在子线程中执行
*
* @param file 文件
* @param start 需要传入 System.currentTimeMillis(),用于兼容遍历的情况
* @return true:已写完 false:外部程序阻塞或者文件不存在
*/
public boolean isFileCompleted(File file, long start) {
if (!file.exists())
return false;
long fileLength = 0;
int i = 0;
logger.info("正在根据日志文件大小监测数据文件是否入库完成(入库成功与否请等待入库完成后查看本程序输出的日志报告), 请稍候...");
while (true) {
//文件在外部一直在填充数据,每次进入循环体时,文件大小都会改变,一直到不改变时,说明文件数据填充完毕 或者文件大小一直都是0(外部程序阻塞)
//判断文件大小是否有改变
if (file.length() > fileLength) { //有改变说明还未写完
fileLength = file.length();
if (i % 120 == 0) { //每隔1分钟输出一次日志 (i为120时:120*500/1000=60秒)
logger.info("日志文件: " + file.getName() + " 正在被填充,请稍候...");
}
try {
Thread.sleep(500);//半秒后再循环一次
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
} else { //否则:只能等于 不会小于,等于有两种情况,一种是数据写完了,一种是外部程序阻塞了,导致文件大小一直为0
if (file.length() != 0) {
//被填充完成则立即输出日志
logger.info("日志文件: " + file.getName() + " 被填充完成,即将输出该日志报告");
break;//写完了 退出当前循环体 执行下面的 return true
} else { //等待外部程序开始写 只等60秒 120*500/1000=60秒
//每隔1分钟输出一次日志 (i为120时:120*500/1000=60秒)
if (i % 120 == 0) {
logger.info("日志文件: " + file.getName() + " 大小为0,正在等待外部程序填充,已等待:" + (System.currentTimeMillis() - start) + "毫秒");
}
//如果一直(i为120时:120*500/1000=60秒)等于0,说明外部程序阻塞了
if (i == 3600) { //120为1分钟 3600为30分钟
logger.info("日志文件: " + file.getName() + " 大小在 :"
+ (System.currentTimeMillis() - start) + "毫秒内始终为0,说明:在 程序监测时间内 入库进程依旧在进行 ,程序监测时间结束");//入库未完成或发生阻塞
return false;
}
//等待外部程序开始写
try {
Thread.sleep(500);
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
}
i++;
}
return true;
}
调用示例:
isFileCompleted(new File("xxx.log"), System.currentTimeMillis())
注:
为什么不用以下代码来判断是否入库完成?:
int result = process.waitFor();
原因:
在 Linux 下调用外部命令(Shell命令),或者可执行的二进制文件,
Java 中依赖 Process 和 Runtime 两个类,查看官方API:
Process 抽象类中是通过 ProcessBuilder.start() 和 Runtime.exec 两个方法来创建本地进程的,
创建的子进程是没有他们自己的 terminal 或者 console 的。
所有标准的 I/O 都会重定向到父进程,
并且通过方法 getOutStream(), getInputStream(), 和 getErrorStram(),
分别获得标准输出,输入和错误流。
由于 JVM 提供标准输入和输出流的缓冲区大小十分有限,
很快的读入或者输出流将会导致进程阻塞或者锁死