资讯专栏INFORMATION COLUMN

Java IO (二),常见的输入/输出流

lidashuang / 2646人阅读

摘要:字节流和字符流和和两个抽象类是所有输入流的基类本身并不能创建实例来执行输入但它们将成为所有输入流的模板他们的方法是所有输入流都可用的方法中包含如下三个方法从输入流中读取单个字节返回所读取的字节数据字节数据可直接转换为类型从输入流中读取最多个

字节流和字符流 InputStream和Reader

InputStream和Reader两个抽象类是所有输入流的基类,本身并不能创建实例来执行输入,但它们将成为所有输入流的模板.他们的方法是所有输入流都可用的方法.

InputStream中包含如下三个方法

int read() 从输入流中读取单个字节,返回所读取的字节数据(字节数据可直接转 换为int类型).

int read(byte[] b) 从输入流中读取最多b.lenght个字节数据,并将其存贮在数组b中,返回实际读取的字节数.

int read(byte[] b,int off,int len) 从输入流中读取最多的len个字符的数据,并存在数组b中,放入数组b中时,从off的位置开始,返回实际读取的字节数.

Reader中包含如下三个方法

int read() 从输入流中读取单个字符,返回所读取的字符数据(字符数可以直接转换为int类型)

int read(char[] cbuf) 从输入流中读取最多的cbuf.length个字符数据,并将其存储在字符数组cbuf中,返回实际读取的字符数.

int read(char cbuf,int off,int len) 从输入流中读取最多len个字符的数据,并将其存在cbuf中,从off位置开始,返回实际的读取的字符数.

使用FileInputStream读取自身

javapublic void readFile() throws IOException {
    //创建字节输入流
    FileInputStream fis = new FileInputStram("FileInputTest.java");
    //创建一个长度为1024的缓冲数组
    byte[] bbuf = new byte[1024];
    //保存实际读取的字节数
    int hasRead = 0;
    //循环读取文件内容
    while ((hasRead = fis.read(bbuf)) > 0) {
       System.out.println(new String(bbuf,0,hasRead));
    }
    //文件IO资源不属于内存资源
    //垃圾回收无法回收该资源
    //必须显式关闭
    fis.close();
}

使用FileReader读取文件自身

public void readFile() throws IOException {
    FileReader fr = new FileReader("FileReaderTest.java");
    char[] cbuf = new char[32];
    int hasRead = 0;
    while ((hasRead = fr.read(cbuf)) > 0) {
        System.out.println(new String(cbuf,0,hasRead));
    }
    fr.clse();
}

此外,InputStream和Reader还支持如下几个方法来支持指针的移动
void mark(int readAheadLimit) 在记录指针当前位置记录一个标记(mark).
boolean markSupported() 判断此输入流是否支持mark()操作
void reset() 将此流的记录指针重新定位到上一次记录标记的位置(mark).
long skip(long n) 记录指针向前移动n个字节/字符.

OutputStream和Writer OutputStream和Writer也非常相似,两个流都提供了如下三个方法:

void write(int c) 将指定的字节/字符输出到输出流中,其中c既可以代表字节,也可以代表字符.

void write(byte[]/char[] buf) 将字节数组/字符数组中的数据输出到指定输出流中.

void write(byte[]/char[] buf,int off,int len) 将字节数组/字符数组从off位置开始,长度为len的字节/字符输出到输出流中.

Writer里还包含如下两个方法:
* void write(String str) 将str字符串输出到指定输出流中
* void write(String str,int off,int len) 将str字符串里从off位置开始,长度为len输出到指定输出流中.

下面的程序使用FileInputStream来执行输入,通过FileOutputStream执行输出,实现复制文件的功能

javapublic void copyFile() throws IOException {
    FileInputStream fis = null;
    FileOutputStream fos = null;

    try {
        fis = new FileInputStream("outfile.txt");
        fos = new FileOutputStream("newfile.txt");

        byte[] bbuf = new byte[32];
        int hasRead = 0;
        while ((hasRead =fis.read(bbuf)) > 0) {
            fos.write(bbuf,0,hasRead);
        }
    } catch(IOException ioe) {
        ioe.printStatckTrance();
    } finally {
        if (fis != null) {
            fis.close();
        }
        if(fos != null) {
            fos.close();
        }
    }
}

如果希望直接输出字符串内容,使用Writer更为方便.

javapublic void out() {
    FileWriter fw = null;
    try {
        fw = new FileWrite("file.txt");
        fw.write("但我不能放歌,
");
        fw.write("悄悄是别离的笙箫;
");
        fw.write("夏虫也为我沉默,
");
        fw.write("沉默是今晚的康桥!
");
    } catch (IOException ioe) {

    } finally {
        if(null != fw) {
            fw.close();
        }
    }
}

上面程序会在当前目录下输出file.txt,文件内容就是程序中输出内容.

输入/输出流体系
分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
访问字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedRead BufferedWriter
转换流 InputStreamReader OutputStreamReader
对象流 ObjectInputStream ObjectOutput
抽象基类 FilterInputStream FilterOutPutStream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

上面表中粗体字标出类的代表节点流,必须直接与指定物理节点关联;斜体字标出的为抽象基类,无法创建实例.

字节流比字符流功能强大,因为计算机中所有数据都是二进制的.字节流可以处理所有的二进制文件.如果使用字节流来处理文本文件时,需要使用合适的方式把字节转换成字符,无形中增加了编程的复杂程度.所以通常有个规则,如果需要进行输入/输出的是文本内容,应考虑使用字符流,如果需要进行输入/输出的二进制内容,应考虑使用字节流.

使用字符串作为物理节点:

javapublic void StringNodeTest() {

    String src = "软泥上的青荇,
"
                +"油油的在水底招摇;
"
                +"在康河的柔波里,
"
                +"我甘心做一条水草。";

    StringReader sr = new StringReader(src);
    char[] cbuf = new char[32];
    int hasRead = 0;
    try {
        while((hasRead =sr.read(cbuf)) > 0) {
            System.out.println(new String(cbuf,0,hasRead));
        }
    } catch (IOException ioe) {
        ioe.
    } finally {
        if (null != sr){
            sr.close();
        }
    }
}
转换流

IO体系中提供了2个转换流,用于实现将字节流转换成字符流.InputStreamReader将字节输入流转换成字符输入流,OutputStreamWriter将字节输出流转换成字符输出流.

Java并没有提供字符流转换成字节流接口,看似设计遗漏.考虑下字符流和字节流的差别,字节流比字符流使用范围更广,但字符流操作比字节流方便,如果已经有一个字符流,为什么还要换成字节流,既然知道字节流的内容是文本,那么转换成字符流更方便一些,所以Java没有提供字符流到字节流的转换.

下面的例子通过使用键盘输入(System.in).这个标准的输入流是InputStream实例,使用起来不太方便,键盘输入的都是纯文本,使用InputStreamReader将其转换为字符输入流,普通Reader读起来依旧不方便,于是再转换成BufferedReader,利用它的readLine()方法可以一次读一行.

javapublic void convInput() {
    BufferedReader br = null;

    try {
        //System.in转换成Reader对象
        InputStreamReader reader = new InputStreamReader(System.in);
        //将Reader包装成BufferedReader
        br = new BufferedReader(reader);
        String buffer = null;
        While((buffer = br.readLine()) != null) {
            if("exit".equals(buffer)) {
                System.exit(1);
            }
            System.out.println("输入内容为:" + buffer);
        }
    } catach (IOException ioe) {

    } finally {
        try {
            if (null != br) {
                br.close();
            }
        } catach (IOException ioe) {

        }
    }
}
推回输入流

在IO体系中,有2个特殊的流.PushbackInputStream和PushbackReader.提供如下三个方法:
* void unread(byte[]/char[] buf) 将一个字节数组内容推回到推回缓冲区里,从而允许重复读取刚刚的内容.
* void unread(byte[]/char[] b,int off,int len) 将一个字节/字符数组从off开始,长度为len字节/ 字符的内容推回到推回缓冲区里,从而允许重复读取刚刚的内容.
* void unread(int b) 将一个字节/字符推回到推回缓冲区,从而允许重复读取刚刚读取的内容.

这三个方法和InputStream和Reader里三个read方法一一对应,这两个推回输入流都带有一个推回缓冲区,当程序调用这两个推回输入流的unread方法时,系统会把指定数组的内容推回到该缓冲区里,从而允许重复读取刚刚读取的内容.

java/**省略无数代码**/

PushbackReader pr = null;

        try {
            pr = new PushbackReader(new FileReader("E:workplace1
eviewsrcioPushbackReaderTest.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("new PushbackReader")) > 0) {
                    //将本次内容上次内容一起退回到推回缓冲区
                    pr.unread((lastContent + content).toCharArray());
                    //再次读取指定程度的内容(目标字符串之前的内容)
                    pr.read(buf,0,targetIndex);
                    //打印读取内容
                    System.out.println(new String(buf,0,targetIndex));
                    System.exit(0);
                } else {
                    System.out.println(lastContent);
                    lastContent = content;
                }
            }

/**省略无数代码**/
重定向标准输入/输出

Java的标准输入输出分别通过System.in和System.out来代表,默认情况下他们分别代表键盘和显示器.
System类中提供三个重定向输入/输出标准的方法:
* static void setErr(PrintStream err) 重定向"标准"错误输出流
* static void setIn(InputStream in) 重定向"标准"输入流
* static void setOut(PrintStream out) 重定向"标准"输出流

下面的程序通过重定向标准输出流,将System.out的输出重定向到到文件输出:

java/**省略无数代码**/
        PrintStream ps = null;

        try {
            //创建重定向需要的输出流
            ps = new PrintStream(new FileOutputStream("out.txt"));
            //将标准输出流重定向到ps输出流
            System.setOut(ps);
            //测试输出
            System.out.println("普通字符串");
            System.out.println(new RedirectOut());
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (null != ps) {
                ps.close();
            }
        }
/**省略无数代码**/

下面的程序通过重定向标准输入流,将System.in重定向到指定文件而不是键盘:

java/**省略无数代码**/
        FileInputStream fis = null;

        try {
            fis = new FileInputStream("E:workplace1
eviewsrcioRedirectIn.java");
            //将标准输入重定向到fis输入流
            System.setIn(fis);
            //获取标准输入
            Scanner sc = new Scanner(System.in);
            //设置只把回车作为分隔符
            sc.useDelimiter("
");
            while (sc.hasNext()) {
                System.out.println("键盘输入内容为:" + sc.next());
            }
/**省略无数代码**/

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64415.html

相关文章

  • 乐字节Java之file、IO基础知识和操作步骤

    摘要:流分类由此可见,流很庞大从不同角度进行分类数据分类按处理数据单位分为字节流和字符流。处理数据是音频视频文本等一切为字节流,仅能处理文本的为字符流。功能分类节点流和处理流。从向一个特定的设备磁盘网络等读写数据的流称为节点流,也常被称为低级流。 嗨喽,小乐又来了,今天要给大家送上的技术文章是Java重点知识-IO流。 先来看看IO流的思维导图吧。showImg(https://segmen...

    pkhope 评论0 收藏0
  • 快速Get-JAVA-IO

    摘要:除非文件用自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流。 第四阶段 IO IO流 前言: 前面的学习我们只能够在已有的一定封闭范围内进行一些操作,但是这显然是无趣的,也是不支持我们实现一些复杂的需求,所以Java提供IO流这样一种概念,方便我们对数据进行操作 而使用IO流我们可以实现一些强大的功能,例如针对文件的移动复制等操作,又或者程序与外部文件之间的数据存储或者读...

    wangzy2019 评论0 收藏0
  • 关于Java IO与NIO知识都在这里

    摘要:从通道进行数据写入创建一个缓冲区,填充数据,并要求通道写入数据。三之通道主要内容通道介绍通常来说中的所有都是从通道开始的。从中选择选择器维护注册过的通道的集合,并且这种注册关系都被封装在当中停止选择的方法方法和方法。 由于内容比较多,我下面放的一部分是我更新在我的微信公众号上的链接,微信排版比较好看,更加利于阅读。每一篇文章下面我都把文章的主要内容给列出来了,便于大家学习与回顾。 Ja...

    Riddler 评论0 收藏0
  • Java 序列化和反序列化

    摘要:把字节序列恢复为对象的过程称为对象的反序列化。代表对象输入流,它的方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。接口继承自接口,实现接口的类完全由自身来控制序列化的行为,而仅实现接口的类可以采用默认的序列化方式。 把对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为对象的过程称为对象的反序列化。    对象的序列化主要有两种用途:   1) 把...

    jcc 评论0 收藏0

发表评论

0条评论

lidashuang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<