[十万火急]高分求救。java调用linux命令问题。

jackingod 技术架构  2009-12-04 09:07:04
问题说明:
1.程序(web)需要实现一个客户端来备份服务器数据库的功能。
2.数据库是postgresql,备份命令在linux下为:/usr/local/pgsql/bin/pg_dump dbname -U dbuser >要保存的路径文件(如:./aaa.dmp);
3.现通过Runtime.getRuntime().exec()命令来执行。

代码如下:

backupCmd = "/usr/local/pgsql/bin/pg_dump books2 -n books_"
+ sch_id + " -U postgres -c >" + address + "books_" + sch_id + "_" + num + ".dmp";

process = Runtime.getRuntime().exec(backupCmd);

System.out.print(Utils.loadStream(process.getInputStream()));
System.err.print(Utils.loadStream(process.getErrorStream()));

Utils.loadStream()的代码:

public static String loadStream(InputStream in) throws IOException {

int ptr = 0;
try {
in = new BufferedInputStream(in);
StringBuffer buffer = new StringBuffer();
while ((ptr = in.read()) != -1) {
buffer.append((char)ptr);
}

return buffer.toString();
} catch (IOException ioe) {
ioe.printStackTrace();
throw ioe;
}
}

程序无反应。并报出错误如下:
java.lang.NullPointerException
at org.apache.jsp.jsp.error.errorPage_jsp._jspService(errorPage_jsp.java:96)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:704)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:476)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:409)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:396)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:301)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:147)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:300)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:374)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:743)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:675)
at org.apache.jk.common.SocketConnection.runIt(ChannelSocket.java:866)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
at java.lang.Thread.run(Thread.java:534)

2009-12-03 13:25:57 org.apache.catalina.core.StandardHostValve@6270b: Exception Processing ErrorPage[errorCode=404, location=/jsp/error/errorPage.jsp]
org.apache.jasper.JasperException
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:372)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:704)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:476)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:409)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:396)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:301)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:147)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:300)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:374)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:743)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:675)
at org.apache.jk.common.SocketConnection.runIt(ChannelSocket.java:866)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
at java.lang.Thread.run(Thread.java:534)


还请高手指点。

...全文
633 点赞 收藏 36
写回复
36 条回复
whut_lcy 2009年12月08日
首先恭喜楼主解决了问题~~~~
个人观点:
毕竟类似Linux,Windows之类的OS都是基于C的实现,而且都预留了对C接口的系统调用库,可以直接嵌入在C代码中调用,但JAVA对OS的系统调用方面就没有这么方便,只能曲线一下,很有限的进行系统调用

有一年多没做JAVA了,现在搞VxWorks嵌入式开发,对C和操作系统之间的关系有一定了解。感觉如果要深入了解JAVA,还是抽点时间学学C比较好。主要是把C的指针搞透彻对JAVA学习和理解非常有利
回复 点赞
jackingod 2009年12月08日
正如楼上所说,确实用调用shell脚本搞定。
空指针后来看了服务器输出,是别的错误导致。
忙了几天终于有了结果,发现自己对Java的很多东西还真的不熟悉,还的多多加油,谢谢在坐各位xdjm了。
回复 点赞
jackingod 2009年12月08日
嗯,多谢楼上兄弟,C一直是梦想,却没什么机会去学习,虽说时间挤挤就有,但是一直没有什么时间来系统的学一下C,有机会一定好好了解一下,语言之间其实是共同的,只要真正精通一门,即便是高级语言去了解他的源代码的话,还是会有很大的收获的。
回复 点赞
jackingod 2009年12月07日
即时flush也不行,还是备份不完全。
现在想换一种思路,用java调用shell脚本,不知道是不是效率高点。
感觉这个还真麻烦。现在本地没有安装数据库,调试起来一点都不方便。
回复 点赞
wmolirong 2009年12月07日
try 可以解决~~
回复 点赞
whut_lcy 2009年12月07日
在while循环里面进行flush
可以控制一下当读取了一定字节数后再进行flush
回复 点赞
jackingod 2009年12月07日
os变量是类的私有变量,现在代码改为如下:

public synchronized void run() {
try {
int byteread = 0;
BufferedOutputStream bufOut = null;
byte[] buffer = new byte[1024 * 2];;

BufferedInputStream bufIn = new BufferedInputStream(is);

if(null != os) bufOut = new BufferedOutputStream(os);

while ((byteread = bufIn.read(buffer)) != -1)
{
if (null != bufIn) bufOut.write(buffer, 0, byteread);
System.out.println(buffer);
}

if (null != bufOut) {
bufOut.flush();
bufOut.close();
}
bufIn.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}

不过还是有问题啦。
回复 点赞
whut_lcy 2009年12月07日
你及时flush一下
回复 点赞
jackingod 2009年12月07日
服务器的jvm内存已经设置为:

JAVA_OPTS="-server -Xmx512m -Xms128m -Djava.awt.headless=true"

应该不是内存的问题吧?
回复 点赞
笨沙发 2009年12月07日
备份不完全是不是设置内存变量太小了
回复 点赞
whut_lcy 2009年12月07日
[Quote=引用 19 楼 wizard_zj 的回复:]
多谢楼上兄弟指点,现在好像已经不是这个原因了。因为现在没用这个方法了。而是参考网上一位大侠的,
用了public class StreamGobbler extends Thread;

Java codepublicvoid run() {try {int byteread=0;
BufferedOutputStream bufOut=null;byte[] buffer=newbyte[1024*4];;

BufferedInputStream bufIn=new BufferedInputStream(is);if(null!= os) bufOut=new BufferedOutputStream(os);while ((byteread= bufIn.read(buffer))!=-1)
{if (null!= bufIn) bufOut.write(buffer,0, byteread);
System.out.println(buffer);
}if (null!= bufOut) bufOut.close();
bufIn.close();
}catch (IOException ioe) {
ioe.printStackTrace();
}
}
[/Quote]

你现在的解决办法引用了线程,这样处理比较好,效率高,不过要注意同步问题,避免带来数据的不一致
run方法里面用了os变量,不知是类变量还是实例变量,这里要注意一下。
在你代码核心部分加一个synchronized块吧
回复 点赞
liangwansheng 2009年12月07日
高手太多,看来没我说话的份了。
学习一下吧。
回复 点赞
jackingod 2009年12月07日
现在就是备份的时候,数据多的时候,文件备份不完全。
还有就是恢复的时候,不知道要怎么写:

StreamGobbler outputGobbler = new StreamGobbler(bufIn, "OUTPUT", process.getOutputStream());


outputGobbler.start();

这样做好像有问题。
回复 点赞
jackingod 2009年12月07日
调用改成:

StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR");
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", fos);

errorGobbler.start();
outputGobbler.start();
回复 点赞
jackingod 2009年12月07日
多谢楼上兄弟指点,现在好像已经不是这个原因了。因为现在没用这个方法了。而是参考网上一位大侠的,
用了public class StreamGobbler extends Thread;


public void run() {
try {

int byteread = 0;
BufferedOutputStream bufOut = null;
byte[] buffer = new byte[1024 * 4];;

BufferedInputStream bufIn = new BufferedInputStream(is);

if(null != os) bufOut = new BufferedOutputStream(os);

while ((byteread = bufIn.read(buffer)) != -1)
{
if (null != bufIn) bufOut.write(buffer, 0, byteread);
System.out.println(buffer);
}

if (null != bufOut) bufOut.close();
bufIn.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
回复 点赞
whut_lcy 2009年12月07日
public static String loadStream(InputStream in) throws IOException {

int ptr = 0;
try {
in = new BufferedInputStream(in); StringBuffer buffer = new StringBuffer();
while ((ptr = in.read()) != -1) {
buffer.append((char)ptr);
}

return buffer.toString();
} catch (IOException ioe) {
ioe.printStackTrace();
throw ioe;
}
}

红色的地方有问题。
in是你方法的入参,你却在方法内部给它赋值然后又修改了。这样毫无用处。空指针就是这里产生的。

如果不想用带缓冲读,直接删除红色那一行;如果一定要用带缓冲读可以修改为:
重新申明一个BufferdInputStream的局部变量
BufferedInputStream bis = new BufferedInputStream(in);

以下用bis代替in进行操作

建议你去学习一下C,了解一下函数参数传递方式:值传递与引用传递(java是值传递)。C有指针,所以函数可以改变入参,java没有指针,你想这样修改入参肯定是错的
回复 点赞
jackingod 2009年12月07日
楼上的高手说的好简单啦,现在发现这样直接调用有问题,当数据比较多时,备份的文件总是不完全。
还原的话好像比备份还难点,希望高手们多支支招。
多谢了。
回复 点赞
whut_lcy 2009年12月07日
你说文件大的时候备份不完全,又看了你的输入输出流是从Runtime获取的,中间所有数据都在你的Runtime中缓存。Runtime能够获取多少内存?

还是用java调用系统shell命令,肯定比java直接操作效率高,而且安全。类似你在终端手动输入shell命令一样。


回复 点赞
jackingod 2009年12月07日
晕,还是被卡住了,哪位写过类似功能的给点意见啦。多谢了。
回复 点赞
poikill 2009年12月07日
学习了
回复 点赞
发动态
发帖子
Web 开发
创建于2007-09-28

5.2w+

社区成员

34.1w+

社区内容

Java Web 开发
社区公告
暂无公告