java 输入输出(四) 重定向标准输入/输出 java虚拟机读写其他进程的数据 RandomAccessFile

1. 重定向标准输入/输出

重定向标注输入/输出即为将默认键盘输入和显示器输出修改为文件输入/输出或其他方式。

Java的标准输入/输出分别通过System.in和System.out来代表,在默认情况下它们分别代表键盘和显示器,当程序通过system.in来获取输入时,实际上是从键盘读取输入;当程序试图通过System.out执行输出时,程序总是输出到屏幕。
在System类里提供了如下3个重定向标准输入/输出的方法。
static void setErr(PrintStream err):重定向“标准"错误输出流。
static void setln(InputStream in):重定向“标准"输入流。
static void setOut(PrintStream out):重定向“标准"输出流。

示例:重定向标准输出流,将System.out的输出重定向到文件输出,而不是在屏幕上输出。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class RedirectOut {
	public static void main(String[] args) {
		
		try {
			// 一次性创建PrintStream输出流
			PrintStream ps = new PrintStream(new FileOutputStream("out.txt"));
			
			// 将标准输出重定向到ps输出流
			System.setOut(ps);
			
			// 向标准输出输出一个对象;  ---  输出不再输出到屏幕(控制台),输出到out.txt文件中
			System.out.println(new RedirectOut());
			
			ps.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}
输出:打开out.txt文件,可看到上述程序的地址。
示例:重定向标准输入,将System.in的输入重定向到指定文件,而不是键盘输入
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;

public class RedirectIn {
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("D:\\workspace02\\study\\src\\com\\oath\\demo03\\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());
		}
		sc.close();
	}
}
输出: 程序将输出该程序自身内容,以行分割。

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

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

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

不仅如此,也可以通过Process的getOutputStream()方法获得向进程输入数据的流(该流对Java程序是输出流,对子进程则是输入流)。

示例:在Java程序中启动Java虚拟机运行另一个Java程序,并向另一个Java程序中输入数据。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;

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();
		}
	}
}
输出:这段代码好像有问题,执行WriteToProcess类,并未有out.txt文件产生;执行ReadStandard类,才有文件产生。

3. RandomAccessFile(任意访问,不是随机访问)

RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,它提供了众多的方法来访问文件内容,它既可以读取文件内容,也可以向文件输出数据。与普通的输入/输出流不同的是,RandomAccessFile支持“随机访问”的方式,程序可以直接跳转到文件的任意地方来读写数据
因为RandomAccessFiIe可以自由访问文件的任意位置,所以如果我们希望只访问文件部分内容,而不是把文件从头读到尾,使用RandomAccessFiIe将是更好的选择。
与OutputStream、Writer等输出流不同的是,RandomAccessFiIe允许自由定位文件记录指针,所以RandomAccessFiIe可以不从开始的地方开始输出,所以RandomAccessFiIe可以向已存在的文件后追加内容。因此,如果程序需要向已存在的文件后追加内容,则应该使用RandomAccessFiIe。
RandomAccessFiIe对象也包含了一个记录指针,用以标识当前读写处的位置,当程序新创建一个RandomAccessFiIe对象时,该对象的文件记录指针位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFiIe可以自由移动该记录指针,既可以向前移动,也可以向后移动。RandomAccessFile包含了如下两个方法来操作文件记录指针。
long getFiIePointer():返回文件记录指针的当前位置。
void seek(long pos):将文件记录指针定位到pos位置

RandomAccessFiIe既可以读文件,也可以写,所以它既包含了完全类似于Inputstream的3个read()方法,其用法和Inputstream的3个read()方法完全一样;
也包含了完全类似于Outputstream的3个write()方法,其用法和Outputstream的3个write()方法完全一样。除此之外,RandomAccessFile还包含了一系列的read-Xxx()和writeXxx()方法来完成输入、输出。
RandomAccessFiIe类有两个构造器,其实这两个构造器基本相同,只是指定文件的形式不同而已一一一个使用String参数来指定文件名,一个使用File参数来指定文件本身。除此之外,创建RandomAccessFiIe对象时还需要指定一个mode参数,该参数指定RandomAccessFiIe的访问模式,该参数有如下4个值。
"r":以只读方式打开指定文件。如果试图对该RandomAccessFile执行写入方法,都将抛出IOException异常。
“rw”:以读、写方式打开指定文件。如果该文件尚不存在,则尝试创建该文件。
“rws”:以读、写方式打开指定文件。相对于"rw"模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
“rwd”:以读、写方式打开指定文件。相对于"rw"模式,还要求对文件内容的每个更新都同步写入到底层存赭设备。

示例:使用RandomAccessFiIe来访间指定的中间部分数据。
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileTest {
	public static void main(String[] args) throws IOException {
		RandomAccessFile raf = new RandomAccessFile("D:\\workspace02\\study\\src\\com\\oath\\demo03\\RandomAccessFileTest.java", "r");
		
		//获取RandomAccessFile对象文件指针的位置,初始位置是0
		System.out.println("RandomAccessFile对象文件指针的位置:" + raf.getFilePointer());
		
		// 移动raf文件记录指针的位置
		raf.seek(300);
		
		byte[] bbuf = new byte[1024];
		
		// 用于保存实际读取的字节数
		int hasRead = 0;
		
		//使用循环重复读取
		while((hasRead = raf.read(bbuf)) > 0){
			System.out.println(new String(bbuf, 0, hasRead));
		}
		
		raf.close();
	}
}
输出:输出程序300字节出后面的内容
RandomAccessFile对象文件指针的位置:0
ileTest.java", "r");
		
		//获取RandomAccessFile对象文件指针的位置,初始位置是0
		......
示例: 如何向指定文件后追加内容,需要先将记录指针移到文件最后面,然后向文件中输出内容
import java.io.IOException;
import java.io.RandomAccessFile;

public class AppendContent {
	public static void main(String[] args) throws IOException {
		// 以读、写方式打开一个RandomAccessFile对象
		RandomAccessFile raf = new RandomAccessFile("out.txt", "rw");
		
		// 将记录指针移到文件最后面
		raf.seek(raf.length());
		raf.write("追加的内容!\r\n".getBytes());
		raf.write("追加的内容!\r\n".getBytes());
		
		raf.close();
	}
}
输出:打开out.txt文件,显示
追加的内容!
追加的内容!

注意:RandomAccessFile 依然不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某位置后开始输出,则新输出的内容会覆盖文件中原有的内容。如果需要向指定位置插入内容,程序需要先把插入点后面的内容读入缓冲区等把需要插入的数据写入文件后,再将缓冲区的内容追加到文件后面。

示例:向指定文件、指定位置插入内容。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

public class InsertContent {
	public static void insert(String fileName, long pos, String insertContent) throws IOException{
		File tmp = File.createTempFile("tmp", null);
		tmp.deleteOnExit();
		
		RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
		// 创建一个临时文件用来保存插入点后的数据
		 FileOutputStream tmpOut = new FileOutputStream(tmp);
		 FileInputStream tmpIn = new FileInputStream(tmp);
		 
		 raf.seek(pos);
		 // -----下面代码将插入点后的内容读入临时文件中保存------
		 byte[] bbuf = new byte[64];
		 // 用于保存实际读取的字节数
		 int hasRead = 0;
		 // 使用循环方式读取插入点后的数据
		 while((hasRead = raf.read(bbuf)) > 0){
			 // 将读取的数据写入临时文件
			 tmpOut.write(bbuf, 0, hasRead);
		 }
		 // ----- 下面代码 用于插入内容 -------
		 // 把文件记录指针重新定位到pos位置
		 raf.seek(pos);
		 // 追加需要插入的内容
		 raf.write(insertContent.getBytes());
		 // 追加临时文件中的内容
		 while((hasRead = tmpIn.read(bbuf)) > 0){
			 raf.write(bbuf, 0, hasRead);
		 }
		 raf.close();
		 tmpOut.close();
		 tmpIn.close();
	}
	public static void main(String[] args) throws IOException {
		insert("D:\\workspace02\\study\\src\\com\\oath\\demo03\\InsertContent.java", 45, "插入的内容\r\n");
	}
	
}
输出:程序执行后会在自身45字节处添加字符串“插入的内容”
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值