Java基础——IO(1)

来源:互联网 发布:淘宝里的极有家是什么 编辑:程序博客网 时间:2024/06/10 15:31

IO流

概述

Java中采用IO流的方式来进行数据传输,IO流分为两种:

    1)字节流的抽象基流:InputStream和OutputStream    2)字符流的抽象基流:Reader和Writer

P.S.

此四个类派生出来的子类名称都是以父类名作为子类名的后缀,以前缀为其功能;如InputStream子类FileInputStream;Reader子类FileReader 记住:如果要操作文字数据,建议优先考虑字符流。    而且要将数据从内存写到硬盘上,要使用字符流中的输出流:Writer。    硬盘的数据基本体现是文件,希望找到一个可以操作文件的Writer:FileWriter

字符流

字符流输入:

用例:

public class Test1 {    public static void main(String[] args) throws IOException {        File file = new File("d://IO");        if(!file.exists()){            //不存在则创建路径            file.mkdirs();        }        FileWriter fw = new FileWriter(file+"/123.txt");        fw.write("你好,字符流输入!");        //刷新缓存到指定文件        fw.flush();        fw.close();    }}

若更改为:FileWriter fw = new FileWriter(file+”/123.txt”,true);

表示: 如果为 true,则将字节写入文件末尾处,而不是写入文件开始处 。

加ture常用来进行文件续写。

字符流输出

1.单个字符读取

public class Test2 {    public static void main(String[] args) throws IOException {        FileReader fr = new FileReader("d://IO/123.txt");        int c = 0;        while((c= fr.read())!=-1){            //这里read的返回值是char值的int型,可以转型为char类型            System.out.print((char)c);        }    }}

2.字符数组读取

public class Test3 {    public static void main(String[] args) throws IOException {        FileReader fr = new FileReader("d://IO/123.txt");        char []c = new char[1024];        //返回值是读取的长度        int len = fr.read(c);            System.out.println(new String(c, 0, len));    }}

练习:

需求: 将d盘一个文本文件复制到f盘、 复制的原理: 其实就是将c盘下的文件数据存储到e盘的一个文件中。 步骤: 1、在e盘创建一个文件。用于存储c盘文件中的数据。 2、定义读取流和c盘文件关联。 3、通过不断的读写完成数据存储。 4、关闭资源。
/**单字符传输*/public class Test4 {    public static void main(String[] args) throws IOException {        FileReader fr = new FileReader("D:\\IO\\123.txt");        FileWriter fw = new FileWriter("f:\\copy123.txt");        //单个字符传送        int c ;        while((c=fr.read())!=-1){            /**public void write(int c)             * c - 指定要写入字符的 int。             */            fw.write(c);        }        fr.close();        fw.close();    }}
public class Test5 {    public static void main(String[] args) throws IOException {        FileReader fr = new FileReader("D:\\IO\\123.txt");        FileWriter fw = new FileWriter("f:\\copy123.txt");        // 字符数组传送        char[] c = new char[1024];        String buf = null;        int len = 0;        while ((len = fr.read(c)) != -1) {            buf = new String(c, 0, len);            fw.write(buf);        }        fw.close();        fr.close();    }}

字符流的缓冲区——BufferedReader和BufferedWriter

使用注意:

1.使用缓冲区技术是为了解决性能问题,提高效率2.需要先建立流对象,再将流对象交给缓冲区构造函数去处理3. 记住,只要用到缓冲区,就要记得刷新。(关闭流同样会刷新,但为了排除意外事故,保证数据存在,建议写入一次就刷新一次)     如:bufw.flush();4.小知识:BufferedWriter缓冲区中提供了一个跨平台的换行符:newLine();可以在不同操作系统上调用,用作数据换行。    如:bufw.newLine();5.读取流缓冲区BufferedReader     BufferedReader.readLine():另外开辟了一个缓冲区,存储的是原缓冲区一行的数据,不包含换行符。所以实际使用中常使用BufferedReader.newLine();方法换行

练习:使用字符缓冲区复制文本

public class Test6 {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new FileReader("D:\\IO\\Hello.java"));        BufferedWriter bw = new BufferedWriter(new FileWriter("f:\\CopyHello.java"));        String buf = null;        while((buf = br.readLine())!=null){            bw.write(buf);            //添加换行,否则输出文本没有格式            bw.newLine();            // //使用缓冲区的刷新方法将数据刷目的地中         }        bw.close();        br.close();    }}

练习:模仿一个BufferedReader的readLine方法

/*需求:根据readLine方法原理,模拟BufferedReader写一个自己的MyBufferedReader*/import java.io.*;//自定义缓冲类class MyBufferedReader extends Reader{    private Reader r;//定义接收的流对象    MyBufferedReader(Reader r)    {        this.r=r;    }    //自定义整行读取    public String myReadLine()throws IOException    {        //创建一个容器,用来存储一行的字符        StringBuilder sb =new StringBuilder();        //一个字符一个字符读取        for (int ch=0;(ch=r.read())!=-1 ; )        {                                            if(ch=='\r')//如果遇到回车符换行符,则继续                continue;            if(ch=='\n')//如果遇到换行符,表示该行读取完毕                return sb.toString();            else                sb.append((char)ch);//将该行的字符添加到容器        }        if(sb.length()!=0)//如果读取结束,容器中还有字符,则返回元素            return sb.toString();        return null;    }    //复写父类中的抽象方法    public int read(char[] cbuf, int off, int len) throws IOException    {        return r.read(cbuf,off,len);    }    //复写父类的close方法    public void close()throws IOException    {        r.close();    }}//测试MyBufferedReaderpublic class  Test7{    public static void main(String[] args)     {        MyBufferedReader mbr=null;        try        {            mbr=new MyBufferedReader(new FileReader("D:\\IO\\Hello.java"));            for (String line=null;(line=mbr.myReadLine())!=null ; )            {                System.out.println(line);//显示效果            }        }        catch (IOException e)        {            throw new RuntimeException("读取数据失败");        }        finally        {            try            {                if(mbr!=null)                    mbr.close();            }            catch (IOException e)            {                throw new RuntimeException("读取流关闭失败");            }        }       }}

LineNumberReader

此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。 换行符('\n')、回车符('\r')
/*需求:利用LineNumberReader的特有方法去设置和获取文件中数据的行号*/public class Test8 {    public static void main(String[] args) {        LineNumberReader lnr = null;        try {            // 将读取流对象传入            lnr = new LineNumberReader(new FileReader("D:\\IO\\Hello.java"));            lnr.setLineNumber(10);// 设置开始行号            for (String line = null; (line = lnr.readLine()) != null;) {                System.out.println(lnr.getLineNumber() + ":" + line);// 打印每行行号和字符            }        } catch (IOException e) {            throw new RuntimeException("读取数据失败");        } finally {            try {                if (lnr != null)                    lnr.close();            } catch (IOException e) {                throw new RuntimeException("读取流关闭失败");            }        }    }}

装饰设计模式

通过多态进行一个功能的增强,不要仅仅使用继承,而应多使用多态。

字节流

1.基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。2.由于媒体文件数据中都是以字节存储的,所以,字节流对象可直接对媒体文件的数据写入到文件中,而可以不用再进行刷流动作。3.读写字节流:InputStream   输入流(读)             OutputStream  输出流(写)

练习:复制图片等媒体资源

public class Test1 {    public static void main(String[] args) throws IOException {        InputStream in = new FileInputStream("d:\\IO\\ME.JPG");        OutputStream out = new FileOutputStream("f:\\CopyME.JPG");        /**         * 另种写法:不推荐          * byte []b= new byte[in.available()];         * 若in.available()值过大,会导致内存溢出         *  p.s.         *  in.available():返回文件中的字节个数         */        // 推荐写法,自定义字符缓冲区        byte[] b = new byte[1024];        int len = 0;        while ((len = in.read(b)) != -1) {            out.write(b, 0, len);        }        out.close();        in.close();    }}

字节流缓冲区

练习:自定义字节流读取缓冲区

/* 自定义字节流读取缓冲区 思路: 1、定义一个固定长度的数组 2、定义一个指针和计数器用于读取数组长度,和计数数组元素是否取完为0 3、每次将字节数据存入元素要先将数组中的元素取完 */  /*自定义字节流读取缓冲区思路:1、定义一个固定长度的数组2、定义一个指针和计数器用于读取数组长度,和计数数组元素是否取完为03、每次将字节数据存入元素要先将数组中的元素取完*/import java.io.*;class MyBufferedInputStream{       private InputStream in;       private byte[] by=new byte[1024];       private int count=0,pos=0;       MyBufferedInputStream(InputStream in)       {              this.in=in;       }       //自定义读方法,一次读一个字节       public int myRead()throws IOException       {              //通过in对象读取硬盘上数据,并存储by中。              //存储在数组中的数据被读取完,再通过in对象从硬盘上读取数据              if(count==0)              {                     count=in.read(by);                     if(count<0)//文件数据全部被读取出来了                            return -1;                     pos=0;//初始化指针                     byte b=by[pos];                     count--;//每被读一个字节,表示数组中的字节数少一个                     pos++;//指针加1                     return b&255;//返回的byte类型提升为int类型,字节数增加,且高24位被补1,原字节数据改变。                                          //通过与上255,主动将byte类型提升为int类型,将高24位补0,原字节数据不变。                                          //而在输出字节流写入数据时,只写该int类型数据的最低8位。              }              else if(count>0)//如果数组中的数据没被读取完,则继续读取              {                     byte b=by[pos];                     count--;                     pos++;                     return b&0xff;              }              return -1;       }       //自定义关闭资源方法       public void close()throws IOException       {              in.close();       }}//测试自定义输入字节流缓冲区public class Test2{       public static void main(String[] args)        {              long start=System.currentTimeMillis();              //利用字节流的缓冲区进行复制              copy_2();              long end=System.currentTimeMillis();              System.out.println("复制共用时:"+(end-start)+"毫秒");       }       //使用字节流的缓冲区进行复制       public static void copy_2()       {              BufferedOutputStream bout=null;              MyBufferedInputStream bin=null;              try              {                     //关联复制文件输入流对象到缓冲区                     bin=new MyBufferedInputStream(new FileInputStream("d:\\IO\\ME.JPG"));                     //指定文件粘贴位置的输出流对象到缓冲区                     bout=new BufferedOutputStream(new FileOutputStream("f:\\CopyME.JPG"));                     int by=0;                     while((by=bin.myRead())!=-1)                     {                            bout.write(by);//将缓冲区中的数据写入指定文件中                     }              }              catch(IOException e)              {                     throw new RuntimeException("MP3复制失败");              }              finally              {                     try                     {                            if(bin!=null)                                   bin.close();//关闭输入字节流                     }                     catch(IOException e)                     {                            throw new RuntimeException("读取字节流关闭失败");                     }                     try                     {                            if(bout!=null)                                   bout.close();//关闭输出字节流                     }                     catch(IOException e)                     {                            throw new RuntimeException("写入字节流关闭失败");                     }              }       }}

流操作

键盘录入

一、键盘录入

1.标准输入输出流

    System.in:对应的标准输入设备,键盘。    Ssytem.out:对应的是标准的输出设备,控制台。    System.in的类型是InputStream.    System.out的类型是PrintStream是OutputStream的子类FilterOutputStream的子类。

2.改进

由于键盘录入是字节流,效率较低。可不可以使用整行读取,那么需要借助readLine方法,但是这个是字符流的方法。所以,需要将字节流转换成字符流。 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));       BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

练习:

/** * 需求:将键盘录入的数据转换成大写输出,显示在控制台,当输入over时,表示结束 源:键盘录入。 目的:控制台。  */public class Test1 {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));        String s = null;        while((s = br.readLine())!=null){            if(s.equals("over"))                break;            bw.write(s.toUpperCase());            bw.flush();        }    }}

练习:

/** * 需求:想把键盘录入的数据存储到一个文件中。  * 源:键盘  * 目的:文件  * 把录入的数据按照指定的编码表(UTF-8),将数据存到文件中。   * 需求:想要将一个文件的数据打印在控制台上。  * 源:文件  * 目的:控制台  */public class Test2 {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        BufferedWriter bw = new BufferedWriter(new FileWriter("f:\\MyTest.txt"));        String s = null;        while((s = br.readLine())!=null){            if(s.equals("over"))                break;            bw.write(s);            bw.flush();            bw.newLine();        }        bw.close();        br.close();    }}

流的操作规律

1、

    源:键盘录入。     目的:控制台。

2、需求:想把键盘录入的数据存储到一个文件中。

    源:键盘    目的:文件。    使用字节流通向字符流的转换流(桥梁):InputStreamReader

3、需求:想要将一个文件的数据打印在控制台上。

    源:文件    目的:控制台    使用字符流通向字节流的转换流(桥梁):OutputStreamWriter

4、流操作的基本规律:

    最痛苦的就是流对象有很多,不知道该用哪一个。

通过三个明确来完成:

4.1 明确源和目的。

    源:输入流。InputStream  Reader    目的:输出流。OutputStream  Writer

4.2 操作的数据是否是纯文本。

    是:字符流    否:字节流

4.3 当体系明确后,再明确要使用哪个具体的对象。通过设备来进行区分:

    源设备:内存,硬盘,键盘    目的设备:内存,硬盘,控制台

5、规律体现

5.1 将一个文本文件中数据存储到另一个文件中。复制文件。

    1)源:因为是源,所以使用读取流:InputStream和Reader         明确体系:是否操作文本:是,Reader          明确设备:明确要使用该体系中的哪个对象:硬盘上的一个文件。Reader体系中可以操作文件的对象是FileReader          是否需要提高效率:是,加入Reader体系中缓冲区 BufferedReader.           FileReader fr = new FileReader("a.txt");          BufferedReader bufr = new BufferedReader(fr);    2)目的:输出流:OutputStream和Writer         明确体系:是否操作文本:是,Writer          明确设备:明确要使用该体系中的哪个对象:硬盘上的一个文件。Writer体系中可以操作文件的对象FileWriter。          是否需要提高效率:是,加入Writer体系中缓冲区 BufferedWriter           FileWriter fw = new FileWriter("b.txt");          BufferedWriter bufw = new BufferedWriter(fw);

练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。

    1)源:输入流,InputStream和Reader        是否是文本?否,InputStream        源设备:硬盘上的一个文件。InputSteam体系中可以操作文件的对象是FileInputSteam        是否需要提供效率:是,BufferedInputStream           BufferedInputSteambis=newBufferedInputStream(newFileInputStream("c:/users/asus/desktop/1.jpg"));    2)目的:输出流,OutputStream和Writer         是否是文本?否,OutputStream         源设备:硬盘上的文件,FileOutputStream         是否需要提高效率:是,加入BufferedOutputStream           BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream("c:/users/asus/desktop/2.jpg"));

5.2 需求:将键盘录入的数据保存到一个文件中。

    1)源:InputStream和Reader          是不是纯文本?是,Reader           设备:键盘。对应的对象是System.in。——为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成Reader。用Reader体系中转换流,InputStreamReader          InputStreamReaderisr = new InputStreamReader(System.in);         需要提高效率吗?需要,BufferedReader         BufferedReaderbufr = new BufferedReader(isr);   2)目的:OutputStream  Writer         是否是存文本?是!Writer。         设备:硬盘。一个文件。使用 FileWriter。         FileWriter fw = newFileWriter("c.txt");       需要提高效率吗?需要。        BufferedWriter bufw = new BufferedWriter(fw);

5.3 扩展:想要把录入的数据按照指定的编码表(UTF-8)(默认编码表是GBK),将数据存到文件中。

    目的:OutputStream  Writer    是否是存文本?是!Writer。    设备:硬盘上的一个文件。使用 FileWriter。——但是FileWriter是使用的默认编码表:GBK。而存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。    该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流:FileOutputStream    OutputStreamWriter osw =new OutputStreamWriter(newFileOutputStream("d.txt"),"UTF-8");    需要高效吗?需要,BufferedWriter    BufferedWriter bufw = new BufferedWriter(osw);

记住:

   转换流什么使用?   字符和字节之间的桥梁。通常,涉及到字符编码转换时,需要用到转换流。

练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。

    1)源:InputStreamReader        是文本?是:Reader        设备:硬盘。上的文件:FileReader        是否需要提高效率?是:BufferedReader         BufferedReader br=new BufferedReader(newFileReader("1.txt"));    2)目的:OutputStream Writer        是文本?是:Writer        设备:控制台。对应对象System.out。由于System.out对应的是字节流,所以利用OutputSteamWriter转换流        是否提高效率?是:BufferedWriter          BufferedWriter bw =new BufferedWriter(newOutputStreamWriter(system.out));

练习:带编码的流操作

/** * 带编码集的操作 * @author LQX * */public class Test3 {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));        //指定UTF-8编码        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("f://MyTest.java"), "UTF-8");        String s = null;        while((s = br.readLine())!=null){            if(s.equals("over"))                break;            osw.write(s+"\r\n");            osw.flush();                    }    }}
public class Test4 {    public static void main(String[] args) throws IOException {        /*BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("f:\\MyTest.java")));        String s = null;        while((s = br.readLine())!=null){            System.out.println(s);        }*/        //该文件在创建时我指定了编码为UTF-8,所以多出来是乱码        FileReader fr = new FileReader("f:\\MyTest.java");        char []c = new char[1024];/*      int len = 0;        while((len = fr.read(c))!=-1){            System.out.println(new String(c, 0, len));        }*/        //修改后,设定了编码为UTF-8,能正确读出来        InputStreamReader isr = new InputStreamReader(new FileInputStream("f:\\MyTest.java"), "UTF-8");        int len = 0;        while((len = isr.read(c))!=-1){            System.out.println(new String(c, 0, len));        }    }}

什么时候使用流转换?

1.目标设备是字节流,但操作是字符流,使用转换流作为桥梁,提高效率。2.涉及文本字符编码表时,必须使用转换流,因为只有它才提供自定义编码。
0 0
原创粉丝点击