隐藏DOS窗口,并转储DOS窗口的输出信息
我们的产品中间件的启动是由批处理文件开始,这就导致,始终有个DOS窗口,来显示服务器的运行情况。可客户不乐意啊:他们就想万一谁不小心把那窗口给关了,损害了数据,那问题可就大了!这个问题确实是挺有价值的。
首先,我们考虑WINDOWS环境吧,我不认为WINDOWS环境下和*NIX环境下的实现有很大差别。想到以前看到的,听到的,再加上自己的经验,大概有这么集中方式:
包装bat文件为exe文件,然后以后台服务的形式注册
利用windows自带的Wscript.Shell
写个Swing界面小程序,利用多线程,启动应用服务,把DOS窗口替换成应用窗口。
但我们需要考虑另外一点:我们的应用在运行的时候,会向dos窗口输出一些出来的一些信息,这些信息在很多情况下都是很有用的。现在如果把DOS窗口隐藏了,那么那些信息我把他们存放到哪儿呢?我想最好还是以文件的形式保存起来,将来如有问题还可以追查!
现在考虑各种实现方式。包装为exe的形式,也只能在windows环境下运行,并且需要额外的工具;Swing界面小程序这个其实是最可行的,但我这个人比较懒,比较讨厌写界面;利用windows自带的Wscript.Shell,自然也只能依赖于windows环境,后来我想了下,其实这个方案可以和swing界面那个方案有不少东西是可以公用的。最后决定,为了简单期间,偶就先用Wscript.Shell,来做测试了。
实际的情况大致是:
应用服务的启动脚本是/startup.bat 实际中我们可以使用vbs脚本:
dim ws
Set ws = CreateObject("Wscript.Shell")
ws.run "cmd /c /startup.bat >> myServer.log" ,vbhide
Set ws = CreateObject("Wscript.Shell")
ws.run "cmd /c /startup.bat >> myServer.log" ,vbhide
通过这样简单的设置,我们可以做到隐藏DOS窗口,但是,如果我们的应用一下子运行好几个月,那我们的日志文件myServer.log的日积月累地,就太大了。我们在查找问题的时候,也很不容易!所以我们应该想法子把日志文件myServer.log,按时间或者按大小分开存储。这也是我们应用服务器日志的做法。所以,我们需要再做一步中间处理,想想看"appRoot/startup.bat"这一步,我们在程序当中还是可以获得它的输出结果的。看下面java程序:
package nc.client.StartupUtil;
import java.lang.ProcessBuilder;
import java.util.Vector ;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.util.Collections ;
public class NC50StartUtil
{
public static final String logFileNamePrefix = "ncconsolelogs";
public static void main(String[] args)
{
ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/C", args[0]+"/startup.bat");
processBuilder.directory(new File(args[0]));
Process process = null;
try
{
process = processBuilder.start();
BufferedReader datais =
new BufferedReader(
new InputStreamReader( process.getInputStream()));
// 服务器日志目录
String serverLogDirName = args[0] + "/nclogs/server";
File serverLogDir = new File (serverLogDirName);
if (!serverLogDir.exists())
{
serverLogDir.mkdirs();
}
int maxFileIndex = getMaxFileIndex(serverLogDirName).intValue();
File logFile = new File(serverLogDirName+"/ncconsolelogs.log");
if (!logFile.exists())
{
logFile.createNewFile();
}
else
{
// 如果已经存在日志文件,则先把原来的文件归档,然后新创建一个日志文件
StringBuffer oldFileName = new StringBuffer();
oldFileName.append(serverLogDirName);
oldFileName.append("/");
oldFileName.append(logFileNamePrefix).append("[").append(maxFileIndex).append("].log");
logFile.renameTo(new File(oldFileName.toString()));
maxFileIndex++;
//创建新的日志文件
if (!logFile.exists())
{
logFile.createNewFile();
}
}
BufferedWriter writer = new BufferedWriter(new FileWriter(logFile));
// 文件的最大大小是2M
int maxlength = 1024*1024*2;
String c;
while ((c = datais.readLine()) != null)
{
writer.write(c);
writer.newLine();
writer.flush();
// 超过日志文件规定的大小了,则把日志文件归档,然后新创建一个日志文件
if (logFile.length() > maxlength)
{
writer.close();
StringBuffer oldFileName = new StringBuffer();
oldFileName.append(serverLogDirName);
oldFileName.append("/");
oldFileName.append(logFileNamePrefix).append("[").append(maxFileIndex).append("].log");
logFile.renameTo(new File(oldFileName.toString()));
maxFileIndex++;
// 创建新的日志文件
if (!logFile.exists())
{
logFile.createNewFile();
}
writer = new BufferedWriter(new FileWriter(logFile));
}
}
}
catch(IOException e)
{
e.printStackTrace ();
}
}
public static Integer getMaxFileIndex(String ncconsolelogdirname)
{
File ncconsolelogdir = new File(ncconsolelogdirname);
File[] ncconsolelogs = ncconsolelogdir.listFiles(new NcLogFileNameFilter(logFileNamePrefix));
if (ncconsolelogs != null && ncconsolelogs.length > 0)
{
Vector v = new Vector();
for (int i=0, len=ncconsolelogs.length; i startIndex)
{
String index = logFileName.substring (startIndex+1, endIndex);
int ind = -1;
try
{
ind = Integer.parseInt(index);
}
catch(Exception e)
{
}
if (ind > 0)
{
v.add(ind);
}
}
}
if (v.size() > 0)
{
return Collections.max(v) + 1;
}
else
{
return 1;
}
}
return 1;
}
}
package nc.client.StartupUtil;
import java.io.File;
import java.io.FilenameFilter;
// 一个简单的文件名过滤类
public class NcLogFileNameFilter implements FilenameFilter {
private String fileNamePrefix = null;
public NcLogFileNameFilter(String fileNamePrefix)
{
this.fileNamePrefix = fileNamePrefix;
}
public boolean accept(File dir, String name)
{
if (name.toLowerCase().startsWith(fileNamePrefix))
{
return true;
}
return false;
}
}
之后,为了运行方便,我们把这两个类编译后打成可执行的jar包,例如ncstartuputil.jar。并修改vbs脚本为:
dim ws
Set ws = CreateObject("Wscript.Shell")
ws.run "cmd /c java -jar ncstartuputil.jar E:/nchome_zhengshi" ,vbhide
Set ws = CreateObject("Wscript.Shell")
ws.run "cmd /c java -jar ncstartuputil.jar E:/nchome_zhengshi" ,vbhide
如果换做swing界面,其实仅仅需要写另外一个Thread,thread的主体也正式上面static main方法主体,然后通过多线程,可以获得原始start.bat批处理文件的输出,并且把输出的信息放到一个textarea里面显示出来。:-)....