Java 学习之路 之 重定向标准输入/输出 和 Java虚拟机读写其他进程的数据(六十七)

重定向标准输入/输出

Java 的标准输入/输出分别通过 System.in 和 System.out 来代表,在默认情况下它们分别代表键盘和显示器,当程序通过 System.in 来获取输入时,实际上是从键盘读取输入;当程序试图通过 System.out 执行输出时,程序总是输出到屏幕。

在 System 类里提供了如下 3 个重定向标准输入/输出的方法。

static void setErr(PrintStream err):重定向 “标准” 错误输出流。

static void setln(lnputStream in):重定向 “标准” 输入流。

static void setOut(PrintStream out):重定向 “标准” 输出流。

下面程序通过重定向标准输出流,将 System.out 的输出重定向到文件输出,而不是在屏幕上输出。

public class RedirectOut
{
	public static void main(String[] args) 
	{
		try(
			// 一次性创建PrintStream输出流
			PrintStream ps = new PrintStream(new FileOutputStream("out.txt")))
		{
			// 将标准输出重定向到ps输出流
			System.setOut(ps);
			// 向标准输出输出一个字符串
			System.out.println("普通字符串");
			// 向标准输出输出一个对象
			System.out.println(new RedirectOut());
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

上面程序中第 7,10 行代码创建了一个 PrintStream 输出流,并将系统的标准输出重定向到该 PrintStream 输出流。运行上面程序时将看不到任何输出——这意味着标准输出不再输出到屏幕,而是输出到 out.txt 文件,运行结束后,打开系统当前路径下的 out.txt 文件,即可看到文件里的内容,正好与程序中的输出一致。

下面程序重定向标准输入,从而可以将 System.in 重定向到指定文件,而不是键盘输入。

public class RedirectIn
{
	public static void main(String[] args) 
	{
		try(
			FileInputStream fis = new FileInputStream("RedirectIn.java"))
		{
			// 将标准输入重定向到fis输入流
			System.setIn(fis);
			// 使用System.in创建Scanner对象,用于获取标准输入
			Scanner sc = new Scanner(System.in);
			// 增加下面一行将只把回车作为分隔符
			sc.useDelimiter("\n");
			// 判断是否还有下一个输入项
			while(sc.hasNext())
			{
				// 输出输入项
				System.out.println("键盘输入的内容是:" + sc.next());
			}
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}
}

上面程序中第 6,9 行代码创建一个 FilelnputStream 输入流,并使用 System 的 setln() 方法将系统标准输入重定向到该文件输入流。运行上面程序,程序不会等待用户输入,而是直接输出了 Redirectln.java 文件的内容,这表明程序不再使用键盘作为标准输入,而是使用 Redirectln.java 文件作为标准输入源。

Java 虚拟机读写其他进程的数据

我们知道使用 Runtime 对象的 exec() 方法可以运行平台上的其他程序,该方法产生一个 Process 对象,Process 对象代表由该 Java 程序启动的子进程。Process 类提供了如下 3 个方法,用于让程序和其子进程进行通信。

InputStream getErrorStream():获取子进程的错误流。

InputStream getlnputStream():获取子进程的输入流。

OutputStream getOutputStream():获取子进程的输出流。

此处的输入流、输出流非常容易混淆,如果我们试图让子程序读取程序中的数据,那么应该用输入流还是输出流?不是输入流,而是输出流,我们要站在程序的角度来看问题,子进程读取程序的数据,就是让裎序把数据输出到子进程中(就像把数据输出到文件中一样,只是现在由子进程节点代替了文件节点),所以应该使用输出流。

下面程序示范了读取其他进程的输出信息。

public class ReadFromProcess
{
	public static void main(String[] args)
		throws IOException
	{
		// 运行javac命令,返回运行该命令的子进程
		Process p = Runtime.getRuntime().exec("javac");
		try(
			// 以p进程的错误流创建BufferedReader对象
			// 这个错误流对本程序是输入流,对p进程则是输出流
			BufferedReader br = new BufferedReader(new 
				InputStreamReader(p.getErrorStream())))
		{
			String buff = null;
			// 采取循环方式来读取p进程的错误输出
			while((buff = br.readLine()) != null)
			{
				System.out.println(buff);
			}
		}
	}
}

上面程序中的第 7 行代码使用 Runtime 启动了 javac 程序,获得了运行该程序对应的子进程;第 11,12 行代码以 p 进程的错误输入流创建了 BufferedReader,这个输入流的流向如图 15.11 所示。

如图 15.11 所示的数据流对 p 进程(javac 进程)而言,它是输出流;但对本程序(ReadFromProcess)而言,它是输入流——我们衡量输入、输出时总是站在运行本程序所在内存的角度,所以该数据流应该是输入流。运行上面程序,会看到如图 15.12 所示的运行窗口。

不仅如此,也可以通过 Process 的 getOutputStrcam() 方法获得向进程输入数据的流(该流对 Java 程序是输出流,对子进程则是输入流),如下程序实现了在 Java 程序中启动 Java 虚拟机运行另一个 Java 程序,并向另一个 Java 程序中输入数据。

public class WriteToProcess
{
	public static void main(String[] args)
		throws IOException
	{	
		// 运行java ReadStandard命令,返回运行该命令的子进程
		Process p = Runtime.getRuntime().exec("java ReadStandard");
		try(
			// 以p进程的输出流创建PrintStream对象
			// 这个输出流对本程序是输出流,对p进程则是输入流
			PrintStream ps = new PrintStream(p.getOutputStream()))
		{
			// 向ReadStandard程序写入内容,这些内容将被ReadStandard读取
			ps.println("普通字符串");
			ps.println(new WriteToProcess());
		}
	}
}
// 定义一个ReadStandard类,该类可以接受标准输入,
// 并将标准输入写入out.txt文件。
class ReadStandard
{
	public static void main(String[] args)
	{
		try(
			// 使用System.in创建Scanner对象,用于获取标准输入
			Scanner sc = new Scanner(System.in);
			PrintStream ps = new PrintStream(
			new FileOutputStream("out.txt")))
		{
			// 增加下面一行将只把回车作为分隔符
			sc.useDelimiter("\n");
			// 判断是否还有下一个输入项
			while(sc.hasNext())
			{
				// 输出输入项
				ps.println("键盘输入的内容是:" + sc.next());
			}
		}
		catch(IOException ioe)
		{
			ioe.printStackTrace();
		}
	}
}

上面程序中的 ReadStandard 是一个使用 Scanner 获取标准输入的类,该类提供了 main() 方法,可以被运行——但我们不打算直接运行该类,而是由 WriteToProcess 类来运行 ReadStandard 类,在程序第 7 行代码,程序使用 Runtime 的 exec() 方法运行了 java ReadStandard 命令,该命令将运行 ReadStandard 类,并返回运行该程序的子进程;程序的第 11 行代码获得进程 p 的输出流——该输出流对进程 p 是输入流,只是对本程序是输出流,程序通过该输出流向进程 p(也就是 ReadStandard 程序)输出数据,这些数据将被 ReadStandard 类读到。

运行上面的 WriteToProcess 类,程序运行结束将看到产生了一个 out.txt 文件,该文件由 ReadStandard 类产生,该文件的内容由 WriteToProcess 类写入 ReadStandard 进程里,并由 ReadStandard 读取这些数据,并将这些数据保存到 out.txt 文件中。

发布了107 篇原创文章 · 获赞 3 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览