JAVA输入/输出(二)-----输入/输出流体系
一、处理流
处理流可以隐藏底层上的节点流的差异,并对外提供更方便的输入/输出方法,让程序员只需关心高级流的操作
使用PrintStream处理流来包装OutputStream,更加方便输出
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(); } } }
二、输入输出流体
注:下表中红颜色的是抽象类,不能创建对象。粗体部分是节点流,其他就是常用的处理流。
| 流分类 | 使用分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
| 抽象基类 | InputStream |
OutputStream |
Reader | Writer | |
| 节点流 | 访问文件 | FileInputStream | FileOutStream | FileReader | FileWriter |
| 访问数值 | ByteArrayInputStream | ByteArrayOutStream | CharArrayReader | CharArrayWriter | |
| 访问管道 | PipedInputStream | PipedOutStream | PipedReader | PipedWriter | |
| 访问字符串 | StringReader | StringWriter | |||
| 处理流 | 缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
| 转换流 | InputStreamReader | OutputStreamWriter | |||
| 对象流 | ObjectInputStream | ObjectOutputStream | |||
| 抽象基类(过滤) | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | |
| 打印流 | PrintStream | PrintWriter | |||
| 推回输入流 | PushbackInputStream | PushbackReader | |||
| 特殊流 | DataInputStream | DataOutputStream |
三、以数组为物理节点的流(StringReader,StringWriter)
public class PrintStreamTest { public static void main(String[] args) { String src = "从明天起\n" + "你是一个好人\n" + "我不是一个坏人"; char[] buffer = new char[32]; int hasRead = 0; try(StringReader sr = new StringReader(src)) { //循环读取字符串 while((hasRead = sr.read(buffer)) > 0){ System.out.println(new String(buffer,0,hasRead)); } }catch(IOException ioe) { ioe.printStackTrace(); } try(StringWriter sw = new StringWriter()) { sw.write(src); //使用toString()方法返回StringWriter字符串节点的内容 System.out.println(sw.toString()); }catch(IOException ioe) { ioe.printStackTrace(); } } }
三、转换流(InputStreamReader,OutputStreamWriter)
用于实现将字节流转换成字符流。
System.in代表标准输入,即键盘输入。输入的内容是InputStream类的实例,用InputStreamReader将其转换成字符输入流,但是普通的Reader读取时依旧不方便,可以将普通的Reader再次包装成 BufferedReader,利用BufferedReader的readLine()方法可以一次读取一行内容。
public class InputStreamReaderTest { public static void main(String[] args) throws IOException { try(InputStreamReader reader = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(reader)) { String line = null; while((line = br.readLine()) != null) { //当输入为"222"时,程序退出 if(line.equals("222")) { System.exit(1); } System.out.println("输入的内容为:" + line); } }catch(IOException ex){ ex.printStackTrace(); } } }
经常把读取文本内容的输入流包装成BufferedReader,用来方便得读取输入流的文本内容。
四、退回输入流(PushbackInputStream,PushbackReader)
void unread(byte[]/char[] buf):将一个字节/字符数组内容推回缓冲区内
void unread(byte[]/char[] buf, int off, int len):将一个字节/字符数组内容从off开始,长度为len字节 推回缓冲区内
void unread(int b):将一个字节/字符推回缓冲区内
这两个推回输入流都带有一个推回缓冲区,从而允许重复读取刚刚读取的内容。只有完全读取了推回缓冲区的内容后,但还没装满read()所需数组时才会从原输入流中读取。
import java.io.FileReader; import java.io.IOException; import java.io.PushbackReader; public class PushbackTest { public static void main(String[] args) throws IOException { //设置缓冲区长度为64 try(PushbackReader pr = new PushbackReader(new FileReader("aaa.java"),64)) { char[] buf = new char[32]; //用以保存上次读取的字符串内容 String lastContent = ""; int hasRead = 0; //读取文件内容 while((hasRead = pr.read(buf)) > 0) { //将读取的内容转换成字符串 String content = new String(buf,0,hasRead); int targetIndex = 0; //将上次读取的字符串和本次读取的字符串拼起来 //查看是否包含目标字符串,若包含 if((targetIndex = (lastContent + content).indexOf("wo shi hao ren")) > 0) { //将本次内容和上次内容一次推回缓冲区 pr.unread((lastContent + content).toCharArray()); //重新定义一个长度为targetIndex的char数组 if(targetIndex > 32) { buf = new char[targetIndex]; } //再次读取指定长度的内容(目标字符串之前的内容) pr.read(buf,0,targetIndex); //打印读取的内容 System.out.print(new String(buf,0,targetIndex)); System.exit(0); }else { //打印上次读取的内容 System.out.print(lastContent); //将本次内容设置为上次读取的内容 lastContent = content; } } }catch(IOException ex){ ex.printStackTrace(); } } }
五、重定向标准输入/输出
static void setErr(PrintStream err):重定向“标准”错误输出流
static void setIn(PrintStream in):重定向“标准”输入流
static void setOut(PrintStream out):重定向“标准”输出流
重定向标准输出:
import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; public class RedirectOut { public static void main(String[] args){ try(PrintStream ps = new PrintStream(new FileOutputStream("aaa.txt"))){ //将标准输出重定向到ps输出流 System.setOut(ps); System.out.println("测试标准输出重定向"); //向标准输出输出一个对象 System.out.println(new RedirectOut()); }catch(IOException ex) { ex.printStackTrace(); } } }
重定向标准输入:程序不会等待用户输入,而是直接输出了aaa.txt文件的内容
import java.io.FileInputStream; import java.io.IOException; import java.util.Scanner; public class RedirectIn { public static void main(String[] args){ try(FileInputStream fis = new FileInputStream("aaa.txt")){ //将标准输入重定向到fis输入流 System.setIn(fis); Scanner sc = new Scanner(System.in); sc.useDelimiter("\n"); while(sc.hasNext()) { System.out.println("键盘输入的内容是: " + sc.next()); } }catch(IOException ex) { ex.printStackTrace(); } } }
六、Java虚拟机读写其他进程的数据
使用Runtime对象的exec()方法可以运行平台上的其他进程,该方法产生一个Process对象,Process对象是由该Java程序启动的子进程。
Process类提供了三个方法用于程序和子进程进行通信:
InputStream getErrorStream():获取子进程的错误流
InputStream getInputStream():获取子进程的输入流
OutputStream getOutputStream():获取子进程的输出流
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进程则是输出流 try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))){ String buff = null; //采取循环的方式来读取p进程的错误输出 while((buff = br.readLine()) != null) { System.out.println(buff); } } } }
通过Process的getOutputStream()方法获得向进程输入数据的流(该流对Java程序是输出流,对子进程是输入流)
import java.io.*; import java.util.Scanner; public class WriteToProcess { public static void main(String[] args) throws IOException{ Process p = Runtime.getRuntime().exec("java ReadStandard"); //以p进程的输出流创建PrintStream对象 //这个输出流对本程序是输出流,对p进程则是输入流 try(PrintStream ps = new PrintStream(p.getOutputStream())){ //向ReadStandard程序写入内容,这些内容将被ReadStandard读取 ps.println("普通字符串"); ps.print(new WriteToProcess()); } } } //该类可以接收标准输入,并将标准输出写入out.txt文件 class ReadStandard{ public static void main(String[] args){ try(Scanner sc = new Scanner(System.in); PrintStream ps = new PrintStream(new FileOutputStream("aaa.txt"))) { sc.useDelimiter("\n"); while(sc.hasNext()) { ps.println("键盘输入的内容是: " + sc.next()); } } catch (IOException e) { e.printStackTrace(); } } }
七、RandomAccessFile
最丰富的文件内容访问类,程序可以直接跳转到文件的任意地方来读写数据。只能读写文件,不能读写其他IO节点。
long getFilePointer():返回文件记录指针的当前记录
void seek(long pos):将文件记录指针定位到pos位置
两个构造器:一个使用String参数来指定文件名,一个使用File参数来指定文件本身。
创建RandomAccessFile对象还需要一个mode参数,代表访问模式:
"r":读方式 "rw":读写方式
"rws":读写方式,还要求对文件的内容或元数据的每个更新同步写入到底层存储设备
"rwd":读写方式,还要求对文件内容的每个更新都同步写入到底层存储设备
访问文件指定的中间数据:
import java.io.*; public class RandomAccessFileTest { public static void main(String[] args) { try(RandomAccessFile raf = new RandomAccessFile(("aaa.txt"),"r")) { //文件指针的位置,初始为0 System.out.println("RandomAccessFile的文件指针的初始位置: " + raf.getFilePointer()); raf.seek(3); byte[] bbuf = new byte[1024]; int hasRead = 0; while((hasRead = raf.read(bbuf)) > 0) { System.out.println(new String(bbuf,0,hasRead)); } }catch (IOException e) { e.printStackTrace(); } } }
向指定文件追加内容(不能在文件指定位置插入内容,会覆盖文件后面原来的内容):
import java.io.*; public class AppendContent { public static void main(String[] args) { try(RandomAccessFile raf = new RandomAccessFile(("aaa.txt"),"rw")) { raf.seek(raf.length()); raf.write("追加的内容!\r\n".getBytes()); }catch (IOException e) { e.printStackTrace(); } } }
向指定文件、指定位置插入内容:
import java.io.*; 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 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); } //-------下面的代码用于插入内容-------------- raf.seek(pos); raf.write(insertContent.getBytes()); while((hasRead = tmpIn.read(bbuf)) > 0) { raf.write(bbuf,0,hasRead); } } } public static void main(String[] args) throws IOException { insert("aaa.txt",4,"插入的内容\r\n"); } }
浙公网安备 33010602011771号