• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • YouClaw
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
风吹花落泪如雨
博客园    首页    新随笔    联系   管理    订阅  订阅

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");
    }
}

 

posted @ 2018-08-19 15:42  风吹花落泪如雨  阅读(167)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3