Java中使用Runtime和Process类运行外部程序.docx_第1页
Java中使用Runtime和Process类运行外部程序.docx_第2页
Java中使用Runtime和Process类运行外部程序.docx_第3页
Java中使用Runtime和Process类运行外部程序.docx_第4页
Java中使用Runtime和Process类运行外部程序.docx_第5页
免费预览已结束,剩余23页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

/xxpal/articles/824963.htmlJava中使用Runtime和Process类运行外部程序使用Runtime.getRuntime().exec()方法可以在java程序里运行外部程序。 1. exec(String command) 2. exec(String command, String envp, File dir) 3. exec(String cmd, String envp) 4. exec(String cmdarray) 5. exec(String cmdarray, String envp) 6. exec(String cmdarray, String envp, File dir)一般的应用程序可以直接使用第一版本,当有环境变量传递的时候使用后面的版本。其中2和6版本可以传递一个目录,标识当前目录,因为有些程序是使用相对目录的,所以就要使用这个版本。cmd.exe /c start 使用DOS命令(比如dir)时也要使用到调用。如果想与调用的程序进行交互,那么就要使用该方法的返回对象Process了,通过Process的getInputStream(),getOutputStream()和getErrorStream()方法可以得到输入输出流,然后通过InputStream可以得到程序对控制台的输出信息,通过OutputStream可以给程序输入指令,这样就达到了程序的交换功能。用Java编写应用时,有时需要在程序中调用另一个现成的可执行程序或系统命令,这时可以通过组合使用Java提供的Runtime类和Process类的方法实现。下面是一种比较典型的程序模式:12Processprocess=Runtime.getRuntime().exec(.p.exe);3process.waitfor();4在上面的程序中,第一行的“.p.exe”是要执行的程序名,Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象的exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制该子进程的执行或获取该子进程的信息。第二条语句的目的等待子进程完成再往下执行。但在windows平台上,如果处理不当,有时并不能得到预期的结果。下面是笔者在实际编程中总结的几种需要注意的情况: 1、执行DOS的内部命令 如果要执行一条DOS内部命令,有两种方法。一种方法是把命令解释器包含在exec()的参数中。例如,执行dir命令,在NT上,可写成exec(cmd.exe /c dir),在windows95/98下,可写成“command.exe /c dir”,其中参数“/c”表示命令执行后关闭DOS立即关闭窗口。另一种方法是,把内部命令放在一个批命令my_dir.bat文件中,在Java程序中写成exec(my_dir.bat)。如果仅仅写成exec(dir),Java虚拟机则会报运行时错误。前一种方法要保证程序的可移植性,需要在程序中读取运行的操作系统平台,以调用不同的命令解释器。后一种方法则不需要做更多的处理。 2、打开一个不可执行的文件 打开一个不可执行的文件,但该文件存在关联的应用程序,则可以有两种方式。以打开一个word文档a.doc文件为例,Java中可以有以下两种写法: 1exec(start.a.doc);2exec(FilesMicrosoftOfficeofficewinword.exe.a.doc); 显然,前一种方法更为简捷方便。 3、执行一个有标准输出的DOS可执行程序 在Windows平台上,运行被调用程序的DOS窗口在程序执行完毕后往往并不会自动关闭,从而导致Java应用程序阻塞在waitfor()语句。导致该现象的一个可能的原因是,该可执行程序的标准输出比较多,而运行窗口的标准输出缓冲区不够大。解决的办法是,利用Java中Process类提供的方法让Java虚拟机截获被调用程序的DOS运行窗口的标准输出,在waitfor()命令之前读出窗口的标准输出缓冲区中的内容。一段典型的程序如下: 12Strings;3Processprocess=Runtime.getRuntime().exec(cmd/cdirwindows);4BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(process.getInputStream();5while(s=bufferedReader.readLine()!=null)6System.out.println(s);7process.waitfor();/topic/72403那就首先说点Runtime类吧,他是一个与JVM运行时环境有关的类,这个类是Singleton的。我说几个自己觉得重要的地方。1、Runtime.getRuntime()可以取得当前JVM的运行时环境,这也是在Java中唯一一个得到运行时环境的方法。2、Runtime上其他大部分的方法都是实例方法,也就是说每次进行运行时调用时都要用到getRuntime方法。3、Runtime中的exit方法是退出当前JVM的方法,估计也是唯一的一个吧,因为我看到System类中的exit实际上也是通过调用Runtime.exit()来退出JVM的,这里说明一下Java对Runtime返回值的一般规则(后边也提到了),0代表正常退出,非0代表异常中止,这只是Java的规则,在各个操作系统中总会发生一些小的混淆。4、Runtime.addShutdownHook()方法可以注册一个hook在JVM执行shutdown的过程中,方法的参数只要是一个初始化过但是没有执行的Thread实例就可以。(注意,Java中的Thread都是执行过了就不值钱的哦)5、说到addShutdownHook这个方法就要说一下JVM运行环境是在什么情况下shutdown或者abort的。文档上是这样写的,当最后一个非精灵进程退出或者收到了一个用户中断信号、用户登出、系统shutdown、Runtime的exit方法被调用时JVM会启动shutdown的过程,在这个过程开始后,他会并行启动所有登记的shutdown hook(注意是并行启动,这就需要线程安全和防止死锁)。当shutdown过程启动后,只有通过调用halt方法才能中止shutdown的过程并退出JVM。那什么时候JVM会abort退出那?首先说明一下,abort退出时JVM就是停止运行但并不一定进行shutdown。这只有JVM在遇到SIGKILL信号或者windows中止进程的信号、本地方法发生类似于访问非法地址一类的内部错误时会出现。这种情况下并不能保证shutdown hook是否被执行。现在开始看这篇文章,呵呵。首先讲的是Runtime.exec()方法的所有重载。这里要注意的有一点,就是public Process exec(String cmdArray, String envp);这个方法中cmdArray是一个执行的命令和参数的字符串数组,数组的第一个元素是要执行的命令往后依次都是命令的参数,envp我个人感觉应该和C中的execve中的环境变量是一样的,envp中使用的是name=value的方式。1、 一个很糟糕的调用程序,代码如下,这个程序用exec调用了一个外部命令之后马上使用exitValue就对其返回值进行检查,让我们看看会出现什么问题。import java.util.*;import java.io.*;public class BadExecJavacpublic static void main(String args)try Runtime rt = Runtime.getRuntime();Process proc = rt.exec(javac);int exitVal = proc.exitValue();System.out.println(Process exitValue: + exitVal); catch (Throwable t)t.printStackTrace();A run of BadExecJavac produces: E:classescomjavaworldjpitfallsarticle2java BadExecJavacjava.lang.IllegalThreadStateException: process has not exitedat java.lang.Win32Process.exitValue(Native Method)at BadExecJavac.main(BadExecJavac.java:13)这里看原文就可以了解,这里主要的问题就是错误的调用了exitValue来取得外部命令的返回值(呵呵,这个错误我也曾经犯过),因为exitValue这个方法是不阻塞的,程序在调用这个方法时外部命令并没有返回所以造成了异常的出现,这里是由另外的方法来等待外部命令执行完毕的,就是waitFor方法,这个方法会一直阻塞直到外部命令执行结束,然后返回外部命令执行的结果,作者在这里一顿批评设计者的思路有问题,呵呵,反正我是无所谓阿,能用就可以拉。但是作者在这里有一个说明,就是exitValue也是有好多用途的。因为当你在一个Process上调用waitFor方法时,当前线程是阻塞的,如果外部命令无法执行结束,那么你的线程就会一直阻塞下去,这种意外会影响我们程序的执行。所以在我们不能判断外部命令什么时候执行完毕而我们的程序还需要继续执行的情况下,我们就应该循环的使用exitValue来取得外部命令的返回状态,并在外部命令返回时作出相应的处理。2、对exitValue处改进了的程序import java.util.*;import java.io.*;public class BadExecJavac2public static void main(String args)try Runtime rt = Runtime.getRuntime();Process proc = rt.exec(javac);int exitVal = proc.waitFor();System.out.println(Process exitValue: + exitVal); catch (Throwable t)t.printStackTrace();不幸的是,这个程序也无法执行完成,它没有输出但却一直悬在那里,这是为什么那?JDK文档中对此有如此的解释:因为本地的系统对标准输入和输出所提供的缓冲池有效,所以错误的对标准输出快速的写入和从标准输入快速的读入都有可能造成子进程的锁,甚至死锁。文档引述完了,作者又开始批评了,他说JDK仅仅说明为什么问题会发生,却并没有说明这个问题怎么解决,这的确是个问题哈。紧接着作者说出自己的做法,就是在执行完外部命令后我们要控制好Process的所有输入和输出(视情况而定),在这个例子里边因为调用的是Javac,而他在没有参数的情况下会将提示信息输出到标准出错,所以在下面的程序中我们要对此进行处理。import java.util.*;import java.io.*;public class MediocreExecJavacpublic static void main(String args)try Runtime rt = Runtime.getRuntime();Process proc = rt.exec(javac);InputStream stderr = proc.getErrorStream();InputStreamReader isr = new InputStreamReader(stderr);BufferedReader br = new BufferedReader(isr);String line = null;System.out.println();while ( (line = br.readLine() != null)System.out.println(line);System.out.println();int exitVal = proc.waitFor();System.out.println(Process exitValue: + exitVal); catch (Throwable t)t.printStackTrace();程序的运行结果为E:classescomjavaworldjpitfallsarticle2java MediocreExecJavacUsage: javac where includes:-g Generate all debugging info-g:none Generate no debugging info-g:lines,vars,source Generate only some debugging info-O Optimize; may hinder debugging or enlarge class files-nowarn Generate no warnings-verbose Output messages about what the compiler is doing-deprecation Output source locations where deprecated APIs are used-classpath Specify where to find user class files-sourcepath Specify where to find input source files-bootclasspath Override location of bootstrap class files-extdirs Override location of installed extensions-d Specify where to place generated class files-encoding Specify character encoding used by source files-target Generate class files for specific VM versionProcess exitValue: 2哎,不管怎么说还是出来了结果,作者作了一下总结,就是说,为了处理好外部命令大量输出的情况,你要确保你的程序处理好外部命令所需要的输入或者输出。下一个题目,当我们调用一个我们认为是可执行程序的时候容易发生的错误(今天晚上我刚刚犯这个错误,没事做这个练习时候发生的)import java.util.*;import java.io.*;public class BadExecWinDirpublic static void main(String args)try Runtime rt = Runtime.getRuntime();Process proc = rt.exec(dir);InputStream stdin = proc.getInputStream();InputStreamReader isr = new InputStreamReader(stdin);BufferedReader br = new BufferedReader(isr);String line = null;System.out.println();while ( (line = br.readLine() != null)System.out.println(line);System.out.println();int exitVal = proc.waitFor(); System.out.println(Process exitValue: + exitVal); catch (Throwable t)t.printStackTrace();A run of BadExecWinDir produces: E:classescomjavaworldjpitfallsarticle2java BadExecWinDirjava.io.IOException: CreateProcess: dir error=2at java.lang.Win32Process.create(Native Method)at java.lang.Win32Process.(Unknown Source)at java.lang.Runtime.execInternal(Native Method)at java.lang.Runtime.exec(Unknown Source)at java.lang.Runtime.exec(Unknown Source)at java.lang.Runtime.exec(Unknown Source)at java.lang.Runtime.exec(Unknown Source)at BadExecWinDir.main(BadExecWinDir.java:12)说实在的,这个错误还真是让我摸不着头脑,我觉得在windows中返回2应该是没有找到这个文件的缘故,可能windows 2000中只有cmd命令,dir命令不是当前环境变量能够解释的吧。我也不知道了,慢慢往下看吧。嘿,果然和作者想的一样,就是因为dir命令是由windows中的解释器解释的,直接执行dir时无法找到dir.exe这个命令,所以会出现文件未找到这个2的错误。如果我们要执行这样的命令,就要先根据操作系统的不同执行不同的解释程序 或者cmd.exe。作者对上边的程序进行了修改import java.util.*;import java.io.*;class StreamGobbler extends ThreadInputStream is;String type;StreamGobbler(InputStream is, String type)this.is = is;this.type = type;public void run()tryInputStreamReader isr = new InputStreamReader(is);BufferedReader br = new BufferedReader(isr);String line=null;while ( (line = br.readLine() != null)System.out.println(type + + line); catch (IOException ioe)ioe.printStackTrace(); public class GoodWindowsExecpublic static void main(String args)if (args.length 1)System.out.println(USAGE: java GoodWindowsExec );System.exit(1);try String osName = System.getProperty( );String cmd = new String3;if( osName.equals( Windows NT ) )cmd0 = cmd.exe ;cmd1 = /C ;cmd2 = args0;else if( osName.equals( Windows 95 ) )cmd0 = ;cmd1 = /C ;cmd2 = args0;Runtime rt = Runtime.getRuntime();System.out.println(Execing + cmd0 + + cmd1 + + cmd2);Process proc = rt.exec(cmd);/ any error message?StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), ERROR); / any output?StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), OUTPUT);/ kick them offerrorGobbler.start();outputGobbler.start();/ any error?int exitVal = proc.waitFor();System.out.println(ExitValue: + exitVal); catch (Throwable t)t.printStackTrace();Running GoodWindowsExec with the dir command generates: E:classescomjavaworldjpitfallsarticle2java GoodWindowsExec dir *.javaExecing cmd.exe /C dir *.javaOUTPUT Volume in drive E has no label.OUTPUT Volume Serial Number is 5C5F-0CC9OUTPUTOUTPUT Directory of E:classescomjavaworldjpitfallsarticle2OUTPUTOUTPUT10/23/00 09:01p 805 BadExecBrowser.javaOUTPUT10/22/00 09:35a 770 BadExecBrowser1.javaOUTPUT10/24/00 08:45p 488 BadExecJavac.javaOUTPUT10/24/00 08:46p 519 BadExecJavac2.javaOUTPUT10/24/00 09:13p 930 BadExecWinDir.javaOUTPUT10/22/00 09:21a 2,282 BadURLPost.javaOUTPUT10/22/00 09:20a 2,273 BadURLPost1.java. (some output omitted for brevity)OUTPUT10/12/00 09:29p 151 SuperFrame.javaOUTPUT10/24/00 09:23p 1,814 TestExec.javaOUTPUT10/09/00 05:47p 23,543 TestStringReplace.javaOUTPUT10/12/00 08:55p 228 TopLevel.javaOUTPUT 22 File(s) 46,661 bytesOUTPUT 19,678,420,992 bytes freeExitValue: 0这里作者教了一个windows中很有用的方法,呵呵,至少我是不知道的,就是cmd.exe /C +一个windows中注册了后缀的文档名,windows会自动地调用相关的程序来打开这个文档,我试了一下,的确很好用,但是好像文件路径中有空格的话就有点问题,我加上引号也无法解决。这里作者强调了一下,不要假设你执行的程序是可执行的程序,要清楚自己的程序是单独可执行的还是被解释的,本章的结束作者会介绍一个命令行工具来帮助我们分析。这里还有一点,就是得到process的输出的方式是getInputStream,这是因为我们要从Java 程序的角度来看,外部程序的输出对于Java来说就是输入,反之亦然。最后的一个漏洞的地方就是错误的认为exec方法会接受所有你在命令行或者Shell中输入并接受的字符串。这些错误主要出现在命令作为参数的情况下,程序员错误的将所有命令行中可以输入的参数命令加入到exec中(这段翻译的不好,凑合看吧)。下面的例子中就是一个程序员想重定向一个命令的输出。import java.util.*;import java.io.*;/ StreamGobbler omitted for brevitypublic class BadWinRedirectpublic static void main(String args)try Runtime rt = Runtime.getRuntime();Process proc = rt.exec(java jecho Hello World test.txt);/ any error message?StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), ERROR); / any output?StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), OUTPUT);/ kick them offerrorGobbler.start();outputGobbler.start();/ any error?int exitVal = proc.waitFor();System.out.println(ExitValue: + exitVal); catch (Throwable t)t.printStackTrace();Running BadWinRedirect produces: E:classescomjavaworldjpitfallsarticle2java BadWinRedirectOUTPUTHello World test.txtExitValue: 0程序员的本意是将Hello World这个输入重订向到一个文本文件中,但是这个文件并没有生成,jecho仅仅是将命令行中的参数输出到标准输出中,用户觉得可以像dos中重定向一样将输出重定向到一个文件中,但这并不能实现,用户错误的将exec认为是一个shell解释器,但它并不是,如果你想将一个程序的输出重定向到其他的程序中,你必须用程序来实现他。可用java.io中的包。import java.util.*;import java.io.*;class StreamGobbler extends ThreadInputStream is;String type;OutputStream os;StreamGobbler(InputStream is, String type)this(is, type, null);StreamGobbler(InputStream is, String type, OutputStream redirect)this.is = is;this.type = type;this.os = redirect;public void run()tryPrintWriter pw = null;if (os != null)pw = new PrintWriter(os);InputStreamReader isr = new InputStreamReader(is);BufferedReader br = new BufferedReader(isr);String line=null;while ( (line = br.readLine() != null)if (pw != null)pw.println(line);System.out.println(type + + line); if (pw != null)pw.flush(); catch (IOException ioe)ioe.printStackTrace(); public class GoodWinRedirectpublic static void main(String args)if (args.length 1)System.out.println(USAGE java GoodWinRedirect );System.exit(1);try FileOutputStream fos = new FileOutputStream(args0);Runtime rt = Runtime.getRuntime();Process proc = rt.exec(java jecho Hello World);/ any error message?StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), ERROR); / any output?StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), OUTPUT, fos);/ kick them offerrorGobbler.start();outputGobbler.start();/ any error?int exitVal = proc.waitFor();System.out.println(ExitValue: + exitVal);fos.flush();fos.close(); catch (Throwable t)t.printStackTrace();Running GoodWinRedirect produces: E:classescomjavaworldjpitfallsarticle2java GoodWinRedirect test.txtOUTPUTHello WorldExitValue: 0这里就不多说了,看看就明白,紧接着作者给出了一个监测命令的小程序import java.util.*;import java.io.*;/ class StreamGobbler omitted for brevitypublic class TestExecpublic static void main(String args)if (args.length java TestExec e:javadocsindex.htmljava.io.IOException: CreateProcess: e:javadocsindex.html error=193at java.lang.Win32Process.create(Native Method)at java.lang.Win32Process.(Unknown Source)at java.lang.Runtime.execInternal(Native Method)at java.lang.Runtime.exec(Unknown Source)at java.lang.Runtime.exec(Unknown Source)at java.lang.Runtime.exec(Unknown Source)at java.lang.Runtime.exec(Unknown Source)at TestExec.main(TestExec.java:45)193在windows中是说这不是一个win32程序,这说明路径中找不到这个网页的关联程序,下面作者决定用一个绝对路径来试一下。E:classescomjavaworldjpitfallsarticle2java TestExec e:program filesnetscapeprogramnetscape.exe e:javadocsindex.htmlExitValue: 0好用了,这个我也试了一下,用的是IE。最后,作者总结了几条规则,防止我们在进行Runtime.exec()调用时出现错误。1、 在一个外部进程执行完之前你不能得到他的退出状态2、 在你的外部程序开始执行的时候你必须马上控制输入、输出、出错这些流。3、 你必须用Runtime.exec()去执行程序4、 你不能象命令行一样使用Runtime.exec()。/base/786384.html如何在Java中执行其它程序在编写Java程序时,有时候需要在Java程序中执行另外一个程序。 1、启动程序Java提供了两种方法用来启动其它程序: (1)使用Runtime的exec()方法 (2)使用ProcessBuilder的start()方法 不管在哪种操作系统下,程序具有基本类似的一些属性。一个程序启动后就程序操作系统的一个进程,进程在执行的时候有自己的环境变量、有自己的工作目录。Runtime和ProcessBuilder提供了不同的方式来启动程序,设置启动参数、环境变量和工作目录。 能够在Java中执行的外部程序,必须是一个实际存在的可执行文件,对于shell下的内嵌命令是不能直接执行的。 采用Runtime的exec执行程序时,首先要使用Runtime的静态方法得到一个Runtime,然后调用Runtime的exec方法。可以将要执行的外部程序和启动参数、环境变量、工作目录作为参数传递给exec方法,该方法执行后返回一个Process代表所执行的程序。 Runtime有六个exec方法,其中两个的定义为: public Process exec(String cmdarray, String envp, File dir) public Process exec(String command, String envp, File dir) cmdarray和command为要执行的命令,可以将命令和参数作为一个字符串command传递给exec()方法,也可以将命令和参数一个一个的方在数组cmdarray里传递给exec()方法。 envp为环境变量,以name=value的形式放在数组中。dir为工作目录。 可以不要dir参数,或者不要envp和dir参数,这样就多出了其它4个exec()方法。如果没有dir参数或者为null,那么新启动的进程就继承当前java进程的工作目录。如果没有envp参数或者为null,那么新启动的进程就继承当前java进程的环境变量。 也可以使用ProcessBuilder类启动一个新的程序,该类是后来添加到JDK中的,而且被推荐使用。通过构造函数设置要执行的命令以及参数,或者也可以通过command()方法获取命令信息后在进行设置。通过directory(File directory) 方法设置工作目录,通过environment()获取环境变量信息来修改环境变量。 在使用ProcessBuilder构造函数创建一个新实例,设置环境变量、工作目录后,可以通过start()方法来启动新程序,与Runtime的exec()方法一样,该方法返回一个Process对象代表启动的程序。 ProcessBuilder与Runtime.exec()方法的不同在于ProcessBuilder提供了redirectErrorStream(boolean redirectErrorStream) 方法,该方法用来将进程的错误输出重定向到标准输出里。即可以将错误输出都将与标准输出合并。 2、Process 不管通过那种方法启动进程后,都会返回一个Process类的实例代表启动的进程,该实例可用来控制进程并获得相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法: (1) void destroy() 杀掉子进程。 一般情况下,该方法并不能杀掉已经启动的进程,不用为好。 (2) int exitValue() 返回子进程的出口值。 只有启动的进程执行完成、或者由于异常退出后,exitValue()方法才会有正常的返回值,否则抛出异常。 (3)InputStream getErrorStream() 获取子进程的错误流。 如果错误输出被重定向,则不能从该流中读取错误输出。 (4)InputStream getInputStream() 获取子进程的输入流。 可以从该流中读取进程的标准输出。 (5)OutputStream getOutputStream() 获取子进程的输出流。 写入到该流中的数据作为进程的标准输入。 (6) int waitFor() 导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。 通过该类提供的方法,可以实现与启动的进程之间通信,达到交互的目的。 、从标准输出和错误输出流读取信息 从启动其他程序的Java进程看,已启动的其他程序输出就是一个普通的输入流,可以通过getInputStream()和getErrorStream来获取。 对于一般输出文本的进程来说,可以将InputStream封装成BufferedReader,然后就可以一行一行的对进程的标准输出进行处理。、举例 ()Runtime.exec()i

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论