输入/输出体系
处理流的用法
使用处理流的典型思路是使用处理流包装节点流,程序通过处理流来执行输入、输出功能,让节点流和底层的IO设备进行交互。
只要流的构造器参数不是一个物理节点,而是一个已存在的流,那么就是出处理流。
举个例子:
package 输入输出体系;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class PrintStreamTest {
public static void main(String []args)
{
try(FileOutputStream fos=new FileOutputStream("test.txt");
PrintStream ps=new PrintStream(fos);
)
{
ps.println("字符串输出");
ps.println(new PrintStreamTest());
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
输出结果如下:
输入、输出流体系
JAVA输入、输出体系提供了近40个类,但整体上还是可以分为输入、输出流,字符流和字节流。(P675)
字节流的功能要比字符流强大,因为计算机里所有数据都是二进制的,而字节流可以处理所有二进制文件,但这样就增加了变成复杂度。
如果进行输入、输出的内容是文本内容,这应该考虑使用字符流;如果进行输入、输出的内容是二进制,则应该考虑字节流。
计算机中所有文件都是二进制文件,而文本文件只是二进制文件的一种特例,当二进制文件的内容恰好能被解析成正常字符时,则二进制文件就变成了文本文件。
如果希望看到正常的文本文件内容,则必须要在打开文件时与保存文件时使用相同的字符集(WINDOWS下简体中文使用GBK字符集,而Linux下简体中文默认使用UTF-8字符集)
以数组为物理节点的节点流除了在创建节点流对象时须臾传入一个字节数组或者字符数组之外,用法上与文件节点流完全一致。
而字符流还可以使用字符串作为物理节点,以实现从字符串读取内容,或将内容写入字符串。
PipedInputStream、PipedOutputStream、PipedReader、PopedWriter都是用来实现进程之间的通信功能的。
而四个缓冲流则增加了缓冲功能,增加缓冲功能可以提高输入、输出的效率,增加缓冲功能后需要使用flush()才可以将缓冲区的内容写入实际的物理节点。
转换流
IO体系提供了两个转换流用于将字节的输入、输出流转化为字符的输入、输出流。
BufferedReader流具有缓冲功能,它可以一次读取一行文本——以换行符为标志,如果它没有读到换行符,则程序阻塞,等到读到换行符为止。
由于BufferedReader具有一个readLine()方法们可以非常方便地一次读入一行内容,所以经常把读取文本内容的输入流包装成BufferedReader,用来方便的读取输出流的文本内容。
推回输入流
字节、字符推回输入流自带有一个推回缓冲区,当程序调用这两个推回方法的unread()方法时,系统将会把指定数组的内容推回到该缓冲区,而推回输入流每次调用调用read()方法时总是先从推回缓冲区读取,只有完全读取了推回缓冲区的内容但还没有装满read()所需的数组时才会从元输出流中读取。
当程序创建PushbackInputStream和PushbackReader时需要指定推回缓冲区的大小,默认的推回缓冲区的长度为1,如果程序推回到推回缓冲区的内容超过了推回缓冲区的大小,则会引发Pushback buffer overflow 的IOException异常。
推回缓冲区的长度和read()方法的数组参数长度没有任何关系。
JAVA虚拟机读取其它进程的数据
使用Runtime对象的exec()方法可以运行平台上的其它程序,该方法产生一个Process对象,Process对象代表由该JAVA程序启动获得的子进程。
输入输出依旧要站在JAVA程序的角度上(可以把子进程节点看成文件节点)。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ReadFromProcess {
public static void main(String[]args)throws IOException
{
Process p=Runtime.getRuntime().exec("javac");
try(
BufferedReader br=new BufferedReader(new InputStreamReader(p.getErrorStream())) )
{
String buff=null;
while((buff=br.readLine())!=null)
{
System.out.println(buff);
}
}
}
}
结果如下:
运行成功
此外,可以通过Process的getOutputStream()方法获得向进程输入数据的流(该流对JAVA程序来说是输出流,对子进程而言是输入流),以下程序实现类在JAVA程序中启动JAVA虚拟机运行另一个JAVA程序,并向其输入数据。
package JVM读取其它进程的数据;
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
{
Process p=Runtime.getRuntime().exec("java ReadStandard");
try
(PrintStream ps=new PrintStream(p.getOutputStream()))
{
ps.println("普通字符串");
ps.println(new WriteToProcess());
}
}
}
class ReadStandard
{
public static void main(String [] args)
{
try(
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 e)
{
e.printStackTrace();
}
}
}
但不幸的是,这个我没弄成功——要么只能转第一个进程,要么只有第二个,第一次运作有这么一个界面:
不能同时选两个,单选一个也不行,这样只会运行那一个,这是Ecplise的情况
用cmd直接来也不行——可以编译,但没法运行,说找不到主类,坑,求大神告知!
RandomAccessFile
RandomAccessFile是JAVA输入、输出流体系中功能最丰富的文件内容访问类,既可以输入也可以输出,此外,RandomAcessFile支持随机访问方式,程序可以直接跳转到文件的任意位置进行读写数据。
如果只需要访问部分文件内容而不是要从头读到尾,那么RandomAccessFile是最好的选择。
如果程序需要往文件尾部追加内容,也应该使用RandomAccessFile。
RandomAccessFile有一个局限——只能读写文件,不能读写其它IO节点。
package Random读取;
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();
try(
RandomAccessFile raf=new RandomAccessFile(fileName,"rw");
FileOutputStream fos=new FileOutputStream(tmp);
FileInputStream fis=new FileInputStream(tmp))
{
raf.seek(pos);
byte []bbuf=new byte[64];
int hasRead=0;
while((hasRead=raf.read(bbuf))>0)
{
fos.write(bbuf);
}
raf.seek(pos);
raf.write(insertContent.getBytes());
hasRead=0;
while((hasRead=fis.read(bbuf))>0)
{
raf.write(bbuf,0,hasRead);
}
}
}
public static void main(String []args)throws IOException
{
insert("InsertContent.java",22,"插入的内容是\r\n");
}
}
运转两次,输出结果为:
运转成功