IO流_1

IO(Input Output)流

用来处理设备之间的数据传输

Java对数据的操作都是通过流的方式

Java用于操作流的对象都在IO包中

流按操作数据分为两种:字节流与字符流

流按流向分为输入流,输出流。

输入流与输出流

输入流和输出流相对于内存设备而言
将外设中的数据读取到内存中:输入
将内存的数据写入到外设中:输出

字符流的由来
其实就是:字节流读取文字字节数据后,不直接操作而是先查指定的编码表。获取对应的文字。
再对这个文字进行操作,简单说:字节流+编码表

字节流的两个顶层父类

InputStream

FilterInputStream

FilterInputStream包含一些其他输入流,它用作其基本的数据源,可能会沿途转换数据或提供附加功能。 FilterInputStream本身简单地覆盖了所有InputStream的方法, InputStream版本将所有请求传递给包含的输入流。 FilterInputStream的FilterInputStream可以进一步覆盖这些方法中的一些,并且还可以提供附加的方法和领域。

int available()    //返回从该输入流中可以读取(或跳过)的字节数的估计,而不会被下一个调用者阻塞该输入流的方法。 
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamDemo {
    public static void main(String[] args)throws IOException{
        demo_write();
        demo_read();
    }
    public static void demo_read()throws IOException{
        //创建一个读取流对象,和指定文件关联
        FileInputStream fis=new FileInputStream("bytedemo.txt");
        /*byte[] buf=new byte[fis.available()];//返回从该输入流中可以读取(或跳过)的字节数的估计,而不会被下一个调用者阻塞该输入流的方法。
       fis.read(buf);
       System.out.println(new String(buf));*/
        byte[] buf=new byte[1024];
        int len=0;
        while ((len=fis.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
        }
        fis.close();
    }
    public static void demo_write() throws IOException{
        //创建字节输出流对象,用于操作文件
        FileOutputStream fos=new FileOutputStream("bytedemo.txt");
        //写数据,直接写入到了目的地中
        fos.write("abcde".getBytes());
    }
}

OutputStream

FilterOutputStream

这个类是过滤输出流的所有类的超类。 这些流位于已经存在的输出流( 底层输出流) 之上 ,它使用它作为数据的基本接收器,但是可能沿着数据方向转换或提供附加功能。

FilterOutputStream本身就简单地覆盖了所有OutputStream的方法, OutputStream版本将所有请求传递给底层输出流。 FilterOutputStream的FilterOutputStream可以进一步覆盖这些方法中的一些,并提供其他方法和字段。

  public static void demo_write() throws IOException{
        //创建字节输出流对象,用于操作文件
        FileOutputStream fos=new FileOutputStream("bytedemo.txt");
        //写数据,直接写入到了目的地中
        fos.write("abcde".getBytes());
    }

 复制mp3的几种方式

package com.monfolld.IO流.ByteStream;

import java.io.*;

public class CopyMp3Test {
    public static void main(String[] args)throws IOException{
        copy_1();
    }
    public static void copy_1()throws IOException{
        FileInputStream fis=new FileInputStream("D:\\CloudMusic\\0.mp3");
        FileOutputStream fos=new FileOutputStream("D:\\CloudMusic\\1.MP2");
        byte[] buf=new byte[1024];
        int len=0;
        while ((len=fis.read(buf))!=-1){
            fos.write(buf,0,len);
        }
        fos.close();
        fis.close();
    }
    public static void copy_2()throws IOException{//建议使用
        FileInputStream fis=new FileInputStream("D:\\CloudMusic\\0.mp3");
        BufferedInputStream bufis=new BufferedInputStream(fis);
        FileOutputStream fos=new FileOutputStream("D:\\CloudMusic\\1.MP2");
        BufferedOutputStream bufos=new BufferedOutputStream(fos);

        int ch=0;
        while ((ch=bufis.read())!=-1){
            bufos.write(ch);
            bufos.flush();
        }
        bufos.close();
        bufis.close();
    }
    public static void copy_3()throws IOException{//不建议
        FileInputStream fis=new FileInputStream("D:\\CloudMusic\\0.mp3");
        FileOutputStream fos=new FileOutputStream("D:\\CloudMusic\\1.MP2");
        byte[] buf=new byte[fis.available()];

        fis.read(buf);
        fos.write(buf);
        fos.close();
        fis.close();
    }
    public static void copy_4()throws IOException{//千万不要有,效率没有
        FileInputStream fis=new FileInputStream("D:\\CloudMusic\\0.mp3");
        FileOutputStream fos=new FileOutputStream("D:\\CloudMusic\\1.MP2");
        int ch=0;
        while ((ch=fis.read())!=-1){
            fos.write(ch);
        }
        fos.close();
        fis.close();
    }

}

字符流的两个顶层父类

Reader

需求:读取一个文本文件。将读取到的字符打印到控制台
同上,找到了FileReader

读取方式一

import java.io.FileReader;
import java.io.IOException;

//需求:读取一个文本文件。将读取到的字打印到控制台
public class FileReaderDemo {
    public static void main(String[] args)throws IOException {
        //1.创建读取字符串数据的流对象
        /*
        * 在创建读取流对象时,必须要明确被读取的文件,一定要确定该文件是否存在
        * 用一个读取流关联一个已存在文件*/
        FileReader fr=new FileReader("demo.txt");
        int ch=0;
        while ((ch=fr.read())!=-1){
            System.out.println((char)ch);
        }
        //用Reader中的read方法读取字符。
        /*int ch=fr.read();
        System.out.println((char) ch);//a
        int ch1=fr.read();
        System.out.println((char) ch1);//b
        int ch2=fr.read();
        System.out.println(ch2);//-1*/
        fr.close();
    }
}

读取方式二

import java.io.FileReader;
import java.io.IOException;

//需求:读取一个文本文件。将读取到的字打印到控制台
public class FileReaderDemo2{
    public static void main(String[] args)throws IOException {
        FileReader fr=new FileReader("demo.txt");
        /*
        * 使用read(char[])读取文本文件数据
        * 先创建字符数组*/
        char[] buf=new char[1024];
        int len=0;
        while ((len=fr.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
        }
        /*int num=fr.read(buf);//将独到的字符存储到数组中
        System.out.println(num+":"+new String(buf,0,num));//3:abc
        int num1=fr.read(buf);//将独到的字符存储到数组中
        System.out.println(num1+":"+new String(buf,0,num1));//2:de*/
        fr.close();
    }
}

Writer

需求:将一些文字存储到硬盘的一个文件中。
记住:如果要操作文字数据,建议优先考虑字符流。
而且要将数据从内存写到硬盘上,要使用字符流中的输出流。Writer
硬盘的数据基本体现是文件,希望找到一个可以操作文件的Writer。
找到了FileWriter

换行和续写

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {
    private static final String LINE_SEPARATOR=System.getProperty("line.separator");
    public static void main(String[] args)throws IOException {
        //创建一个可以往文件中写入字符数据的字符输入流对象
        /*
        * 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确改文件(用于存储数据的目的地)
        * 如果文件不存在,则会自动创建
        * 如果文件存在,则会被覆盖
        *
        * 如果构造函数中加入true,可以实现对文件的续写*/
        FileWriter fw=new FileWriter("demo.txt",true);
        /*
        * 调用Writer对象中的write(string)方法,写入数据
        * 其实数据写入到临时存储缓冲区中*/
        fw.write("ab\rcde");
        //fw.write("abc"+LINE_SEPARATOR+"ABC");
        //fw.flush();//进行刷新,将数据写入目的地中
        fw.close();//关闭流,关闭资源,在关闭前会先调用flush刷新缓冲中的数据到达目的地。
    }
}

IO异常处理

import java.io.FileWriter;
import java.io.IOException;

public class IOExceptionDemo {
    private static final String LINE_SEPARATOR=System.getProperty("line.separator");
    public static void main(String[] args){
        FileWriter fw=null;
        try {
            fw=new FileWriter("k:\\demo.txt",true);
            fw.write("abc"+LINE_SEPARATOR+"ABC");

        }catch (IOException e){
            System.out.println(e.toString());
        }finally {
            if (fw !=null)
            try {
                fw.close();
            }catch (IOException e){
                throw new RuntimeException("关闭失败");
            }
        }
    }
}
结果:
java.io.FileNotFoundException: k:\demo.txt (系统找不到指定的路径。)

练习

复制文本文件

将c盘的一个文本文件复制到d盘

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyTextTest {
    public static void main(String[] args)throws IOException {
        //读取一个已有文本文件,使字符读取流和文件想关联
        FileReader fr=new FileReader("IO流_2.txt");
        //创建一个目的,用于存储读到数据
        FileWriter fw=new FileWriter("copytext_1.txt");
        //频繁的读写操作
        int ch=0;
        while ((ch=fr.read())!=0){
            fw.write(ch);
        }

        //关闭流资源
        fw.close();
        fr.close();
    }
}
import java.io.FileReader;
import java.io.FileWriter;
public class CopyTextTest_2 {
    private static final int BUFFER_SIZE=1024;
    public static void main(String[] args){
        FileReader fr=null;
        FileWriter fw=null;
        try {
            fr=new FileReader("IO流_2.txt");
            fw=new FileWriter("copytext_1.txt");
            //创建一个临时容器,用于缓冲读到的字符
            char[] buf=new char[BUFFER_SIZE];//缓冲区
            //定义一个变量记录读取到的字符数,其实就是往数组里装字符的个数
            int len=0;
            while ((len=fr.read(buf))!=-1){
                fw.write(buf,0,len);
            }
        }catch (Exception e){
            throw new RuntimeException("读写失败");
        }finally {
            if (fw!=null)
                try {
                    fw.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            if (fr!=null)
                try {
                    fr.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
         }
    }
}

字符缓冲区

BufferedWriter

将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。

可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。

提供了一个newLine()方法,它使用平台自己的系统属性line.separator定义的行分隔符概念。 并非所有平台都使用换行符('\ n')来终止行。 因此,调用此方法来终止每个输出行,因此优选直接写入换行符。

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriterDemo {
    public static void main(String[] args)throws IOException {
        FileWriter fw=new FileWriter("buf.txt");
        //为了提高写入的效率,使用字符流的缓冲区
        //创建一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联
        BufferedWriter bufw=new BufferedWriter(fw);//起到一个提高效率的作用
        //使用缓冲区的写入方法,将数据线写入缓冲区中
        /*bufw.write("abcde");
        bufw.newLine();//
        bufw.write("fghij");*/
        for (int x=1;x<=4;x++){
            bufw.write("abcdef"+x);
            bufw.newLine();
            bufw.flush();
        }
        //使用缓冲区的刷新方法将数据刷目的地中
        //bufw.flush();
        bufw.close();//其实关闭的就是被缓冲的流对象
    }
}

BufferedReader

从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。

可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。

每次调用read()或readLine()可能会导致从文件中读取字节,转换成字符,然后返回,这可能非常低效。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferReaderDemo {
    public static void main(String[] args)throws IOException {
       FileReader fr=new FileReader("buf.txt");
        BufferedReader bufr=new BufferedReader(fr);
        String line=null;
        while ((line=bufr.readLine())!=null){
            System.out.println(line);
        }
        /*String line1=bufr.readLine();
        System.out.println(line1);
        String line2=bufr.readLine();
        System.out.println(line2);*/

    }
    public static void demo()throws IOException{
        FileReader fr=new FileReader("buf.txt");
        char[] buf=new char[1024];
        int len=0;
        while ((len=fr.read())!=-1){
            System.out.println(new String(buf,0,len));
        }
        fr.close();
    }
}

利用缓冲区复制文本文件

import java.io.*;
import java.nio.Buffer;

public class CopyTextByBufTest {
    public static void main(String[] args)throws IOException {
        FileReader fr=new FileReader("buf.txt");
        BufferedReader bufr=new BufferedReader(fr);

        FileWriter fw=new FileWriter("bufcopy.txt");
        BufferedWriter bufw=new BufferedWriter(fw);

        String line=null;
        while ((line=bufr.readLine())!=null){
            bufw.write(line);
            bufw.newLine();
            bufw.flush();
        }
        /*int ch=0;
        while ((ch=bufr.read())!=-1){
            bufw.write(ch);
        }*/
        bufw.close();
        bufr.close();
    }
}

自定义MyBufferedReader_read方法

自定义的读取缓冲区,其实就是模拟一个BufferedReadder

分析:缓冲区中无非就是封装了一个数组,并多外提供了更多的方法对数组进行访问,

其实这些方法最终操作的都是数组的指针(角标)。

缓冲的原理:其实就是从源中获取一批数据装进缓冲区中,再从缓冲区中不断的取出一个一个数据,

在此次取完后,再从源中继续取一批数据进缓冲区。当源中的数据取光时,用-1作为结束标记。

package com.monfolld.IO流.buffer;

import java.io.FileReader;
import java.io.IOException;

public class MyBufferedReader {
    private FileReader r;
    //定义一个数组作为缓冲区
    private char[] buf=new char[1024];
    //定义一个指针用于操作这个数组中的元素,当操作最后一个元素后,指针应该归零
    private int pos=0;
    //定义一个计数器用于记录缓冲区的数据个数,当该数据减到0,就从源中继续获取数据到缓冲区中
    private int count=0;
    MyBufferedReader(FileReader r){
        this.r=r;
    }
    public int myRead()throws IOException {
    //1.从源中获取一批数据到缓冲区中,需要先做判断,只有计数器为0时,才需要从源中获取数据
        if (count==0){
            count=r.read(buf);
            //每次获取数据到缓冲区后,角标归零,
            pos=0;
        }if (count<0)
            return -1;
            char ch=buf[pos];
            pos++;
            count--;
            return ch;

    }
    public String myReadLine()throws IOException{
        StringBuilder sb=new StringBuilder();
        int ch=0;
        while ((ch=myRead())!=-1){
            if (ch=='\r')
                continue;
            if (ch=='\n')
                return sb.toString();
            //将从缓冲区得到的字符,存储到缓存行数据的缓冲区中
            sb.append((char)ch);
        }
        return null;
    }
    public void myClose()throws IOException{
        r.close();
    }
}

LineNumberReader

缓冲字符输入流,跟踪行号。 该类定义方法setLineNumber(int)getLineNumber()用于分别设置和获得当前行号。

import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class LineNumberReaderDemo {
    public static void main(String[] args)throws IOException {
        FileReader fr=new FileReader("IO流_2.txt");
        LineNumberReader lnr=new LineNumberReader(fr);
            String line=null;
            lnr.setLineNumber(100);//设置当前行号
            while ((line=lnr.readLine())!=null){
                System.out.println(lnr.getLineNumber()+":"+line);//106:qwerdf
            }
            lnr.close();
    }
}

流转换

InputStreamReader

InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

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

public class TransStreamDemo {
    public static void main(String[] args)throws IOException {
        //字节流
        InputStream in=System.in;
        //将字节转成字符的桥梁
        InputStreamReader isr=new InputStreamReader(in);
        //字符流
        BufferedReader bufr=new BufferedReader(isr);
        String line=null;
        while ((line=bufr.readLine())!=null){
            if ("over".equals(line))
                break;
            System.out.println(line.toUpperCase());
        }
    }
}

OutputStreamWriter

OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节charset 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

        import java.io.*;

public class TransStreamDemo {
    public static void main(String[] args)throws IOException {
        /*InputStream in=System.in;
        InputStreamReader isr=new InputStreamReader(in);
        //字符流
        BufferedReader bufr=new BufferedReader(isr);*/
        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));//键盘录入

        //将字符流转字节
        /*OutputStream out=System.out;
        OutputStreamWriter osw=new OutputStreamWriter(out);
        BufferedWriter bufw=new BufferedWriter(osw);*/
        BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
        String line=null;
        while ((line=bufr.readLine())!=null){
            if ("over".equals(line))
                break;
            bufw.write(line.toUpperCase()+"\r\n");//将字符数据用缓冲区对象将数据写入缓冲区,目的地是osw
            bufw.flush();
         }
    }
}

需求演示

package com.monfolld.IO流;

        import java.io.*;

public class TransStreamDemo {
    public static void main(String[] args)throws IOException {
        /*
        * 1.需求:将键盘录入的数据写入到一个文件中
        *  BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));//键盘录入
          BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("bufcopy.txt")));
        * 2.需求:将一个文本文件内容显示在控制台上
        *BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));//键盘录入
         BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
        * 3:需求:将一个文本文件中的内容复制到另一个文件中*/
        BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));//键盘录入
        BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
        String line=null;
        while ((line=bufr.readLine())!=null){
            if ("over".equals(line))
                break;
            bufw.write(line.toUpperCase()+"\r\n");//将字符数据用缓冲区对象将数据写入缓冲区,目的地是osw
            bufw.flush();
         }
    }
}
流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想知道开发时用到哪些对象,只要通过四个明确即可。
1.明确源和目的(汇)
    源:InputStream Reader
    目的:OutputStream Writer
2.明确数据是否是纯文本数据
    源:是纯文本 Reader
        否:InputStream
    目的:是纯文本 Writer
        否:OutputStream
    到这里,就可以明确需求中具体要使用哪个体系。
3.明确具体的设备
    原设备:
        硬盘:File
        键盘:System.in
        内存:数组
        网络:Socket流
    目的设备:
        硬盘:File
        控制台:System.out
        内存:数组
        网络:Socket流
4.是否需要其他额外功能
    1.是否需要高效(缓冲区);
        是,就加上buffer。

转换流编码解码

import java.io.*;

public class TranStreamDemo3 {
    public static void main(String[] args)throws IOException {
        writeText();
    }
    public static void writeText_2()throws IOException{
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("dbk_2.txt"));
        /*这两句代码的功能是等同的
        * FileWriter:其实就是转换流制定了本机默认码表的体现。而且这个转换流的子类对象,可以方便操作文本文件
        *               简单说:操作文件的字节流+本机默认码表
        *               这是按照默认码表来操作文件的便捷类
        *
        * 如果操作文本文件需要默认明确具体的编码,FileWriter就不行了。必须用转换流*/
        osw.write("你好");
        osw.close();
    }
    public static void writeText_3()throws IOException{
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("u8_1.txt"),"utf-8");
        osw.write("你好");
        osw.close();
    }
    public static void writeText()throws IOException{
        FileWriter fw=new FileWriter("dbk_1.txt");//等同于2
        fw.write("你好");
        fw.close();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值