java要点笔记——IO流


IO流

01-IO流(输入流&输出流)

1、IO(Input  Output)流:IO流用来处理设备之间的数据传输。

2、流,按操作数据分为两种:字节流、字符流。

3、流,按流向分氛围两种:输入流、输出流。

4、哪到哪是输入,哪到哪是输出?

java要点笔记——IO流_第1张图片

把数据往内存里放,是输入。把数据从内存中取出,是输出。输入、输出是相对于内存而言的。

day20 02-IO流(字节流&字符流)

1、数据存储方式全都是以字节为单位的二进制。

2、很简单,字符流的底层就是字节流。而字符流主要是读取文本文件内容的,可以一个字符一个字符的读取,也可以一行一行的读取文本文件内容。而字节流读取单位为byte.byte作为计算机存储最基本单位,可以用字节流来读取很多其他格式的文件,比如图片视频等等。基于B/S和C/S的文件传输都可以采用字节流的形式。

    你可以这样理解:字符比字节要大,也就是分别用这两流时,都作为最小的单位。

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

4、FileReaderfr = new FileReader(“source.txt”);——字符流

    InputStreamReaderisr = new InputStreamReader(new FileInputSTream(“source.txt”,”GBK”);——转换流

    这两句话功能等同,一次可以进一步理解字符流做了什么。字符流确实是先查本地默认码表获得文字后再进行操作。

day20 03-IO流(字符流-FileWriter)

1、IO流框架图

java要点笔记——IO流_第2张图片

2、IO流常用基类(这四个基类全是抽象类,都不能直接用)

    字节流的两个顶层父类:InputStream、OutputStream

    字符流的两个顶层父类:Reader、Writer

3、由这四各类派生出来的子类名称都是以其父类名作为子类名的后缀。

    如:InputStream的子类——FileInputStream

    如:Reader的子类——FileReader

4、需求,将文字"abcde"存储到硬盘的一个文件myText.txt中

5、使用类:

    类FileWriter

        用来写入字符文件的便捷类

 

构造方法摘要

FileWriter(File file)
          根据给定的 File 对象构造一个 FileWriter 对象。

 

FileWriter(File file, boolean append)
          根据给定的 File 对象构造一个 FileWriter 对象。

 

FileWriter(FileDescriptor fd)
          构造与某个文件描述符相关联的 FileWriter 对象。

 

FileWriter(String fileName)
          根据给定的文件名构造一个 FileWriter 对象。

 

FileWriter(String fileName, boolean append)
          根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

 

6、代码示例:

public class AwtDemo18 {
    //创建一个可以往文件中写入字符数据的字符输出流对象
    /*
     * 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)
     * 如果文件不存在,则会自动创建。
     * 如果文件存在,则会被覆盖。
     */
    public static void main(String[] args) throws IOException {
       FileWriter fw = new FileWriter("myText.txt");
       //调用Writer对象中的write(String)方法,写入数据
       fw.write("abcde");
       /*
        * 一运行,打开myText.txt,啥玩意没有,怎么回事?
        * 其实数据写入到了临时存储缓冲区中。(通俗说,是把数据写到“流”里去了)
        * 那我要东到目的地怎么办?进行刷新,将数据直接写到目的地中。
        */
       //fw.flush();
       //close会先刷新再关闭
       fw.close();
    }
}

运行结果:

    系统中多了一个的txt文件,里面内容为。

7、flush()和close()的区别:

    close()就是txt的关闭,flush()就是txt的保存。

    你一点关闭,它让你保存一下。这正如同,你关闭流,但之前会先刷新他。对于流来说,flush()可以多次,close()就一次。你一关,这个流就拜拜了。想再写,你就得再new流。

8、java.io

    类Writer

方法摘要

 Writer

append(char c)
          将指定字符添加到此 writer。

 Writer

append(CharSequence csq)
          将指定字符序列添加到此 writer。

 Writer

append(CharSequence csq, int start, int end)
          将指定字符序列的子序列添加到此 writer.Appendable。

abstract  void

close()
          关闭此流,但要先刷新它。

abstract  void

flush()
          刷新该流的缓冲。

 void

write(char[] cbuf)
          写入字符数组。

abstract  void

write(char[] cbuf, int off, int len)
          写入字符数组的某一部分。

 void

write(int c)
          写入单个字符。

 void

write(String str)
          写入字符串。

 void

write(String str, int off, int len)
          写入字符串的某一部分。

day20 04-IO流(字符流-FileWriter-细节(换行和续写))

1、需求1换行:现在要往一个文本文件中写入。

2、代码示例1:系统通用型不强

public class AwtDemo19 {
    public static void main(String[] args) throws IOException {
       FileWriter fw = new FileWriter("myText.txt");
       fw.write("abcdefg\r\nhijklmn");
       fw.close();
    }
}

运行结果:哦了

3、但是存在这样一个问题。Windows的换行是\r\n,但是Linux的换行是\n。如果这个程序要跨平台,怎么办?方法就是,你这个系统的换行符是什么,我就拿什么。

4、代码示例2:可以跨平台跨系统

public class AwtDemo19 {
    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
    public static void main(String[] args) throws IOException {
       FileWriter fw = new FileWriter("myText.txt");
       fw.write("abcdefg"+LINE_SEPARATOR+"hijklmn");
       fw.close();
    }
}

5、需求2续写:现在要求在需求1完成的txt文件基础上(即前面一个流已经关闭了),再进行续写。写入。

6、如果仍然用:FileWriter fw = new FileWriter("myText.txt");那么原文件会被覆盖,达不到续写的目的。

7、FileWriter类中还有一个构造方法

    FileWriter(String fileName,boolean append)
          根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

8、代码示例

public class AwtDemo19 {
    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
    public static void main(String[] args) throws IOException {
       //使用这个构造方法,表示如果有myText.txt,不覆盖这个文件。而是继续在这个文件中续写。
       FileWriter fw = new FileWriter("myText.txt",true);
       fw.write(LINE_SEPARATOR+"opqrst"+LINE_SEPARATOR+"uvwxyz");
       fw.close();
    }
}

运行结果:。

day20 05-IO流(字符流-FileWriter-IO异常处理)

1、一般只要进行读写,都会发生IO异常。

    如下图,全是红色波浪线。

java要点笔记——IO流_第3张图片

2、IO异常的简单处理方法

public class Demo20 {
    public static void main(String[] args) {//若我在方法上不抛出IO异常,下面3句话全部红线
       FileWriter fw = null;//①把命令放到外面是为了防止局部变量出了范围就没了。因为后面的代码块中还有fw
       try{//②有可能在new对象时就出了问题
           fw = new FileWriter("myText.txt");
           fw.write("abcde");
       }catch(IOException e){//③处理new对象与write()可能会抛的异常。
           System.out.println(e.toString());
       }
       finally{//④close方法之所以放到finally中,是因为必须要关闭资源
           if(fw!= null){//⑤加判断是为了防止空指向异常,因为有可能你new对象时,就完了。对象都没创建,你调用什么close方法
              try {
                  fw.close();
              } catch (IOException e) {//⑥处理close可能会抛出的异常
                  throw new RuntimeException("关闭失败");
              }
           }
          
       }
    }
}


day20 06-IO流(字符流-FileReader-读取方式1-一个字符一个字符的读)

1、需求:读取一个文件,将读取到的字符打印到控制台。

2、FileReader:用来读取字符文件的便捷类。

   

构造方法摘要

FileReader(File file)
          在给定从中读取数据的 File 的情况下创建一个新 FileReader。

 

FileReader(FileDescriptor fd)
          在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。

 

FileReader(String fileName)
          在给定从中读取数据的文件名的情况下创建一个新 FileReader。

 

方法摘要

abstract  void

close()
          关闭该流并释放与之关联的所有资源。

 void

mark(int readAheadLimit)
          标记流中的当前位置。

 boolean

markSupported()
          判断此流是否支持 mark() 操作。

 int

read()
          读取单个字符。

 int

read(char[] cbuf)
          将字符读入数组。

abstract  int

read(char[] cbuf, int off, int len)
          将字符读入数组的某一部分。

 int

read(CharBuffer target)
          试图将字符读入指定的字符缓冲区。

 boolean

ready()
          判断是否准备读取此流。

 void

reset()
          重置该流。

 long

skip(long n)
          跳过字符。

3、假设现在有一个demo.txt的文件,里面的内容:abcd

4、代码示例1——读取1个字符

public class Demo49 {
    public static void main(String[] args) throws IOException {
       //创建读取字符数据的流对象
       /*
        * 在创建读取流对象时,必须要明确被读取的文件,一定要确定该文件是存在的。
        * 用一个读取流关联一个已存在的文件
        */
       FileReader fr = new FileReader("demo.txt");
       //读取单个字符
       int ch = fr.read();
       System.out.println(ch);
       fr.close();
    }
}

    运行结果:97

5、代码示例2——连续读取单个字符

public class Demo49 {
    public static void main(String[] args) throws IOException {
       FileReader fr = new FileReader("demo.txt");
       int ch = 0;
       while((ch=fr.read())!=-1){
           System.out.println(ch);
       }
       fr.close();
    }
}

运行结果:97

        98

        99

        100

6、类Reader中的read方法

    public int read()throws IOException

         读取单个字符。在字符可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。

         用于支持高效的单字符输入的子类应重写此方法。

返回:

作为整数读取的字符,范围在0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1

抛出:

IOException - 如果发生 I/O 错误

7、示意图

day20 07-IO流(字符流-FileReader-读取方式2-先把字符读到缓冲区再从缓冲区拿)

1、类Reader

    public int read(char[] cbuf) throwsIOException

将字符读入数组。在某个输入可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。

参数:

cbuf - 目标缓冲区

返回:

读取的字符数,如果已到达流的末尾,则返回 -1

抛出:

IOException - 如果发生 I/O 错误

2、代码示例1——理解read(char[])的工作方式

public class Demo50 {
    public static void main(String[] args) throws IOException {
       // TODO Auto-generatedmethod stub
       FileReader fr = new FileReader("demo.txt");
       /*
        * 使用read(char[])读取文本文件数据
        * 先创建字符数组
        */
       char[] buf = new char[3];
       int num = fr.read(buf);//将读取到的字符存储到数组中
       System.out.println(num+":"+new String(buf));
       int num1 = fr.read(buf);
       System.out.println(num1+":"+new String(buf));
       int num2 = fr.read(buf);
       System.out.println(num2+":"+new String(buf));
    }
}

运行结果:3:abc

        1:dbc

        -1:dbc

3、图解read(char[])方法

4、代码示例2——利用缓冲区连续进行读取

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

运行结果:abc

        d

5、两种读取方式,哪种好?

    利用缓冲区更好。循环次数少。我吃花生,原来一个一个抓着吃,后来我搞一勺,一勺好几个的吃。明显拿勺子吃更快。

6、定义数组作为缓冲区的时候,长度定多少合适?

    最好就是1024的整数倍。

day20 08-IO流(字符流-练习-复制文本文件1)

1、需求:将一个文本文件复制一份。

2、思路:

    ①这个问题的本质就是连续读写。

    ②需要读取源。

    ③将读到的源数据写入到目的地。

    ④既然是操作文本数据,那么使用字符流。

3、步骤:

    ①读取一个已有的文本文件,使用字符读取流与文件相关联。

    ②创建一个目的,用于存储读到的数据。

    ③频繁的读写操作。

    ④关闭流资源。

4、代码示例1——读一个字符写一个字符

public class Demo53 {
    public static void main(String[] args) throws IOException {
       // TODO Auto-generatedmethod stub
       //1、读取一个已有的文本文件,使用字符读取流和文件相关联。
       FileReader fr = new FileReader("demo_GB.txt");
       //2、创建一个目的,用于存储读到的数据。
       FileWriter fw = new FileWriter("demo3.txt");
       //3、频繁的读写操作。
       int ch = 0;
       while((ch=fr.read())!=-1){
           fw.write((char)ch);
       }
       //4、关闭流资源。
       fr.close();
       fw.close();
    }
}

day20 09-IO流(字符流-练习-复制文本文件2)

1、代码示例2——先读进缓冲数组,再从数组往文件里写

public class Demo54 {
    private static final int BUFFER_SIZE = 1024;
    public static void main(String[] args) {
       FileReader fr = null;
       FileWriter fw = null;
       try{
           fr = new FileReader("demo.txt");
           fw = new FileWriter("demo3.txt");
           //创建一个临时容器,用于缓存读取到的字符
           char[] buf = new char[BUFFER_SIZE];
           //定义一个变量记录读取到的字符数,(其实也是往数组里装的字符个数)
           int len = 0;
           while((len = fr.read(buf))!=-1){
              fw.write(buf,0,len);
           }
       }catch(IOException e){
           System.out.println(e.toString());
       }
       finally{
           if(fr!=null){
              try {
                  fr.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
           }
           if(fw!=null){
              try {
                  fw.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
           }
       }  
    }
}


2、相对来说,代码示例2更好,因为效率更高。

3、两种方式的区别图解

java要点笔记——IO流_第4张图片

day21 11-IO流(字符流-缓冲区-解释)

1、缓冲区的出现提高了对数据的读写效率。

    没有缓冲区,读一次写一次,磁头的切换频率很高。

    有缓冲区,先一通读,再一通写。不用来回进行切换,效率更高。

2、BufferedWriter与BufferedReader工作情况图解

java要点笔记——IO流_第5张图片

day21 12-IO流(字符流-缓冲区-BufferedWriter)

1、类BufferedWriter

   

    将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够了。

构造方法摘要

BufferedWriter(Writer out)
          创建一个使用默认大小输出缓冲区的缓冲字符输出流。

 

BufferedWriter(Writer out, int sz)
          创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

 

 

方法摘要

 void

close()
          关闭此流,但要先刷新它。

 void

flush()
          刷新该流的缓冲。

 void

newLine()
          写入一个行分隔符。(特色方法)

 void

write(char[] cbuf, int off, int len)
          写入字符数组的某一部分。

 void

write(int c)
          写入单个字符。

 void

write(String s, int off, int len)
          写入字符串的某一部分。

2、代码示例1——不用缓冲区,效率低下

public class Demo55 {
    public static void main(String[] args) throws IOException {
       FileWriter fw = new FileWriter("demo.txt");
       fw.write("abcdef");
       fw.close();
    }
}


3、代码示例2——使用缓冲区包装类

public class Demo56 {
    public static void main(String[] args) throws IOException {
       FileWriter fw = new FileWriter("demo1.txt");
       //为了提高写入的效率,使用了字符流的缓冲区。
       //创建了一个字符写入流的缓冲区对象。
       BufferedWriter bufw = new BufferedWriter(fw);
       //使用缓冲区的下入方法,将数据先写入到缓冲区中。
       bufw.write("abcdef");
       //使用缓冲区的刷新方法将数据刷到目的地中。
       bufw.flush();
       //关闭缓冲区
       bufw.close();
    }
}

4、问,这里写了bufw.close();还需要再写fw.close();吗?

    答:不用了!关缓冲区的时候,流也被关掉了。缓冲区仅仅起到了一个提高效率的功能,他没有调用底层资源。真正调用底层资源的是流。BufferedWriter里面的close()方法,写的其实就是:

    void close(){

       fw.close();

    }

5、BufferedWriter类中换行,除了write(System.getProperty("line.separator"))之外。还有另一个方式,就是BufferedWriter的newLine()方法。注意newLine方法只在这个地方具备,别的地方不具备。

6、代码示例1——newLine方法换行

public class Demo57 {
    public static void main(String[] args) throws IOException {
       FileWriter fw = new FileWriter("demo5.txt");
       BufferedWriter bufw = new BufferedWriter(fw);
       bufw.write("abcdefg");
       bufw.newLine();
       bufw.write("higklmn");
       bufw.flush();
       bufw.close();
    }
}

    运行结果:

7、注意:虽然close()带着刷新功能(close关闭此流,但要先刷新它),但是close不能替代flush方法。

8、代码示例1——close不能替代flush方法

 

day21 13-IO流(字符流-缓冲区-BufferedReader)

1、类BufferedReader

    从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

构造方法摘要

BufferedReader(Reader in)
          创建一个使用默认大小输入缓冲区的缓冲字符输入流。

 

BufferedReader(Reader in, int sz)
          创建一个使用指定大小输入缓冲区的缓冲字符输入流。

 

 

方法摘要

 void

close()
          关闭该流并释放与之关联的所有资源。

 void

mark(int readAheadLimit)
          标记流中的当前位置。

 boolean

markSupported()
          判断此流是否支持 mark() 操作(它一定支持)。

 int

read()
          读取单个字符。

 int

read(char[] cbuf, int off, int len)
          将字符读入数组的某一部分。

 String

readLine()
          读取一个文本行。

 boolean

ready()
          判断此流是否已准备好被读取。

 void

reset()
          将流重置到最新的标记。

 long

skip(long n)
          跳过字符。

2、代码示例1——BufferedReader类以及readLine方法

    文件demo.txt——

public class Demo60 {
    public static void main(String[] args) throws IOException {
       FileReader fr = new FileReader("demo01.txt");
       BufferedReader bufr = new BufferedReader(fr);
       String line = null;
       while((line = bufr.readLine())!=null){
           System.out.println(line);
       }
       bufr.close();
    }
}

day21 14-IO流(字符流-缓冲区-BufferedReader-readLine方法原理)

1、查看BufferedReader类中的方法摘要,发现他覆盖了int read()方法,但却没有覆写int read(char[] cbuf)。

2、底层流对象,它从硬盘往外读。缓冲区对象操作的都是缓冲区中的内容。

java要点笔记——IO流_第6张图片

3、由上图可知,readLine方法使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记。将标记前的缓存数据变成字符串返回。

4、缓冲区其实就是在内存当中定义的容器,把硬盘上或者源中的数据,抓一部分放到缓冲区里边来。然后,我们以后再操作的时候,就不再一个个操作硬盘,而是操作内存。取完了,再抓一批进内存。

day21 15-IO流(字符流-缓冲区-复制文本文件)

1、需求:利用缓冲包装类来复制一个文件。

2、代码示例1——从缓冲区一次只读取一个字符

public class Demo61 {
    public static void main(String[] args) throws IOException {
       FileReader fr = new FileReader("buf.txt");
       BufferedReader bufr = new BufferedReader(fr);
      
       FileWriter fw = new FileWriter("buf_copy.txt");
       BufferedWriter bufw = new BufferedWriter(fw);
      
       int ch = 0;
       while((ch = bufr.read())!=-1){
           bufw.write(ch);
       }
       bufw.close();
       bufr.close();
    }
}


3、代码示例2——从缓冲区一次读取一行字符

public class Demo62 {
    public static void main(String[] args) throws IOException {
       FileReader fr = new FileReader("buf.txt");
       BufferedReader bufr = new BufferedReader(fr);
      
       FileWriter fw = new FileWriter("buf_copy2.txt");
       BufferedWriter bufw = new BufferedWriter(fw);
      
       String line = null;
       while((line = bufr.readLine())!=null){
           bufw.write(line);
           bufw.newLine();
       }
       bufr.close();
       bufw.close();
    }
}

day21 16-IO流(字符流-缓冲区-自定义MyBufferedReader-read方法)

1、我想自己实现BufferedReader中的read方法。

2、自定义的读取缓冲区,其实就是模拟一个BufferedReader。

    分析:缓冲区中无非就是封装了一个数组,并对外提供了更多的方法对数组进行访问。其实这些方法最终操作的都是数组的角标。

    缓冲的原理:其实就是从源中获取一批数据装进缓冲区中。再从缓冲区中不断的取出一个个数据。在此次取完后,再从源中继续取一批数据进缓冲区。当源中的数据取光时,用-1作为结束标记。

3、java.io

    类BufferedReader

    方法摘要

       int read()//这一节就是要模拟这个方法

           读取单个字符。(注意是单个!从缓冲区中一次只读取一个字符。别一个循环全给搞完了。读完一个,下次读的时候,他会再读下一个。)

4、代码示例:模拟BufferedReader中的read方法。

day21 17-IO流(字符流-缓冲区-自定义MyBufferedReader-readLine方法)

day21 18-IO流(字符流-缓冲区-装饰设计模式)

1、缓冲区的出现,将源中的数据存储到了我们自定义的数组里边,进行了缓存。并对数组进行操作,而提高了性能。BufferedReader类的出现,对FileReader类进行了功能上的增强。这种增强在设计模式中也有一种体现,叫做装饰设计模式。

2、装饰设计模式:对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。

3、打死都不要过分修改代码,那是灾难。

day21 19-IO流(字符流-缓冲区-装饰设计模式和继承的区别)

1、装饰和继承都能实现一样的特点:进行功能的扩展增强。那么他们有什么区别呢?

2、装饰和继承的区别分析

    首先,我们这里有一个继承体系:

    Writer

       |-TextWriter:用于操作文本

       |-MediaWriter:用于操作媒体

    想要对操作的动作进行效率的提高。按照面向对象,可以通过继承对具体对象进行功能的扩展。比如,我现在需要提高效率,来加入缓冲技术。

    Writer

       |-TextWriter:用于操作文本。

           |-BufferedTextWriter:加入了缓冲技术的操作文本的对象。

       |-MediaWriter:用于操作媒体。

           |-BufferedMediaWriter:加入了缓冲技术的操作媒体的对象。

    但这么做好像并不理想。如果这体系进行功能扩展,又多了。那么是不是要继续产生子类呢?是的!这时就会发现,只为提高功能而进行的继承,导致继承体系越来越臃肿,不够灵活。

    我们重新思考这个问题。

    既然加入的都是同一种技术——缓冲。前一种是让缓冲和具体的对象相结合。可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲相关联。

    如下图示意:

java要点笔记——IO流_第7张图片

    以后,我们的体系就变成这样:

    Writer

       |-TextWriter:用于操作文本。

       |-MediaWriter:用于操作媒体。

       |-BufferedWriter:用于提高效率。

3、装饰比继承更为灵活。

4、特点:装饰类和被装饰类都必须所属同一个接口或者父类。

day21 20-IO流(字符流-缓冲区-LineNumberReader)

1、类LineNumberReader

跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int)getLineNumber(),它们可分别用于设置和获取当前行号。

默认情况下,行编号从 0 开始。该行号随数据读取在每个行结束符处递增,并且可以通过调用 setLineNumber(int) 更改行号。

构造方法摘要

LineNumberReader(Reader in)
          使用默认输入缓冲区的大小创建新的行编号 reader。

 

LineNumberReader(Reader in, int sz)
          创建新的行编号 reader,将字符读入给定大小的缓冲区。

 

 

方法摘要

 int

getLineNumber()
          获得当前行号。

 void

mark(int readAheadLimit)
          标记该流中的当前位置。

 int

read()
          读取单个字符。

 int

read(char[] cbuf, int off, int len)
          将字符读入数组中的某一部分。

 String

readLine()
          读取文本行。

 void

reset()
          将该流重新设置为最新的标记。

 void

setLineNumber(int lineNumber)
          设置当前行号。

 long

skip(long n)
          跳过字符。

2、代码示例1:LineNumberReader是装饰类,有装饰类,那就得有被装饰类。另外注意LineNumberReader继承了Bufferedreader。

public class Demo41 {
    public static void main(String[] args) throws IOException {
       FileReader fr = new FileReader("MyText.txt");
       LineNumberReader lnr = new LineNumberReader(fr);
       String line = null;
       while((line = lnr.readLine())!=null){
           System.out.println(lnr.getLineNumber()+":"+line);
       }
       lnr.close();
    }
}

运行结果:

3、代码示例2——自定义行号开始的数字

public class Demo41 {
    public static void main(String[] args) throws IOException {
       FileReader fr = new FileReader("MyText.txt");
       LineNumberReader lnr = new LineNumberReader(fr);
       String line = null;
       lnr.setLineNumber(100);
       while((line = lnr.readLine())!=null){
           System.out.println(lnr.getLineNumber()+":"+line);
       }
       lnr.close();
    }
}


运行结果:

day21 21-IO流(字节流-操作文件基本演示)

1、字节流:他操作的单位是字节,基本操作与字符流类相同。但他不仅可以操作字符,还可以操作其他媒体文件。

2、字节流与字符流的区别:①无非是它操作的单位不一样。②处理的数据格式也不一样。③字符流只能处理文字。

3、字节流的两个抽象基类

(1)

构造方法摘要

InputStream()
           

 

 

方法摘要

 int

available()
          返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

 void

close()
          关闭此输入流并释放与该流关联的所有系统资源。

 void

mark(int readlimit)
          在此输入流中标记当前的位置。

 boolean

markSupported()
          测试此输入流是否支持 mark 和 reset 方法。

abstract  int

read()
          从输入流中读取数据的下一个字节。

 int

read(byte[] b)
          从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

 int

read(byte[] b, int off, int len)
          将输入流中最多 len 个数据字节读入 byte 数组。

 void

reset()
          将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。

 long

skip(long n)
          跳过和丢弃此输入流中数据的 n 个字节。

(2)

构造方法摘要

OutputStream()
           

 

 

方法摘要

 void

close()
          关闭此输出流并释放与此流有关的所有系统资源。

 void

flush()
          刷新此输出流并强制写出所有缓冲的输出字节。

 void

write(byte[] b)
          将 b.length 个字节从指定的 byte 数组写入此输出流。

 void

write(byte[] b, int off, int len)
          将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

abstract  void

write(int b)
          将指定的字节写入此输出流。

4、代码示例1——利用字节流写数据

public class TestDemo16 {
    public static void main(String[] args) throws IOException {
       //1、创建字节输出流对象,用于操作文件
       FileOutputStream fos = new FileOutputStream("demo.txt");
       //2、写数据。注意,你这里只写"abcdefg"不行!字节流操作字节,你得转化成字节数组。
       //3、直接写入到了目的地中。字节流不用flush。FileOutputStream继承了父类的flush方法,但在方法代码中什么都没写。
       fos.write("abcdefg".getBytes());
       //但是字节流是需要close的。
       fos.close();
    }
}

5、代码示例2——利用字节流读数据

public class TestDemo17 {
    public static void main(String[] args) throws IOException {
       //1、创建一个读取流对象,和指定文件关联
       FileInputStream fis = new FileInputStream("MyText.txt");
       int ch = 0;
       while((ch = fis.read())!=-1){
           System.out.println((char)ch);
       }
       fis.close();
    }
}

6、代码示例3——手动建立一个缓冲区

public class Demo42 {
    public static void main(String[] args) throws IOException {
       FileInputStream fis = new FileInputStream("MyText.txt");
       byte[] buf = new byte[1024];
       int len = 0;
       while((len = fis.read(buf))!=-1){
           System.out.println(new String(buf,0,len));
       }
       fis.close();
    }
}

7、下面介绍一个方法:

 int

available()
          返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。

这个方法,你可以在new缓冲区的时候调用。他会拿所要读取的源文件一样内存大小的数值。

    我在定义字节数组时可以写:byte[] buf = new byte[fis.available()];这个数组大小刚刚好,就是你要读取的文件大小。

    但是这个方法少用。万一我关联了一个2G多的电影,你也去new一个2G大的数组?直接内存溢出!

    所以,在读小文件的时候你可以用。另外,再读文件前你可以先获取这个文件的大小,再分段对这个文件进行读取。

day21 22-IO流(字节流-练习-复制MP3)

day22 23-IO流(演示键盘录入)

1、需求:读取一个键盘录入的数据,并打印在控制台上。

2、

字段摘要

static PrintStream

err
          “标准”错误输出流。

static InputStream

in
          “标准”输入流。

static PrintStream

out
          “标准”输出流。

对于键盘录入,使用的就是in这个字段摘要。

3、代码示例——键盘输入一个打印一个

public class Demo43 {
    public static void main(String[] args) throws IOException {
       InputStream in = System.in;
       int ch1 = in.read();
       System.out.println(ch1);
       int ch2 = in.read();
       System.out.println(ch2);
       int ch3 = in.read();
       System.out.println(ch3);
    }
}

4、以上方法为什么没有关流?in.close()

    从系统获取的流对象,就in一个。你把in一关,再造个in2。不行!没有了。这与其他流对象不同。所以这东西尽量别关,它会随着系统的消失而消失,随着系统的出现而出现。记住,默认的输入设备和默认的输出设备都不需要关。你关了,就再也获取不到了。除非你的系统关掉,重新再启动,才能获取。

day22 24-IO流(读取键盘录入)

1、需求:获取用户键盘录入的数据,并将数据变成大写显示在控制台上。如果用户输入的是over,结束键盘录入。

2、思路:

(1)因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串。

(2)那就需要一个容器,StringBuilder

(3)在用户回车之前,将录入的数据变成字符串判断即可。

3、代码示例

public class Demo44 {
    public static void main(String[] args) throws IOException {
       //1、创建容器
       StringBuilder sb = new StringBuilder();
       //2、获取键盘读取流
       InputStream in = System.in;
       //3、定义变量记录读取到的字节,并循环获取
       int ch = 0;
       while((ch = in.read())!=-1){
           //在存储之前需要判断是否是换行标记,因为换行标记不存储
           if(ch == '\r'){
              continue;
           }
           if(ch == '\n'){
              String temp = sb.toString();
              if("over".equals(temp)){
                  break;
              }
              System.out.println(temp.toUpperCase());
              sb.delete(0,sb.length());
           }else{
              //将读取到的字节存储到StringBuilder中
              sb.append((char)ch);
           }
       }
    }
}

4、结束录入,一般不是点Ctrl+C,而是自定义结束标记。

day22 25-IO流(转换流)

1、上节中的方法很像readLine方法。但字节流不具备readLine方法。readLine方法是BufferedReader的方法。是字符流缓冲区的方法,而这是字节流。

2、能不能把字节流转换成字符流?

3、类InputStreamReader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

构造方法摘要

InputStreamReader(InputStream in)
          创建一个使用默认字符集的 InputStreamReader。

 

InputStreamReader(InputStream in,Charset cs)
          创建使用给定字符集的 InputStreamReader。

 

InputStreamReader(InputStream in,CharsetDecoder dec)
          创建使用给定字符集解码器的 InputStreamReader。

 

InputStreamReader(InputStream in,String charsetName)
          创建使用指定字符集的 InputStreamReader。

 

 

方法摘要

 void

close()
          关闭该流并释放与之关联的所有资源。

 String

getEncoding()
          返回此流使用的字符编码的名称。

 int

read()
          读取单个字符。

 int

read(char[] cbuf, int offset, int length)
          将字符读入数组中的某一部分。

 boolean

ready()
          判断此流是否已经准备好用于读取。

4、代码示例——重写上节中的需求

public class Demo45 {
    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());
       }
    }
}

5、字节流操作与字符流操作的对比,观察区别。文本文件中只有一个“你”字。

6、代码示例1——字节流读取两次

public class TestDemo18 {
    public static void main(String[] args) throws IOException {
       FileInputStream fis = new FileInputStream("test.txt");
       System.out.println(fis.read());
       System.out.println(fis.read());
    }
}

运行结果:196

         227

“你”这个字的GBK(简中Window默认码表)码为C4E3。E3(227),C4(196)。可见,字节流内部不做任何编码转换。

7、代码示例2——字符流读取一次

public class TestDemo19 {
    public static void main(String[] args) throws IOException {
       FileInputStream fis = new FileInputStream("test.txt");
       InputStreamReader fir = new InputStreamReader(fis);
       System.out.println(fir.read());
    }
}

运行结果:20320

“你”这个字的unicode码为4F60,即20320(十进制)。

8、有字节转化成字符的桥梁,那么就应该有字符转化成字节的桥梁。

9、类OutputStreamWriter

    OutputStreamWriter是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

构造方法摘要

OutputStreamWriter(OutputStream out)
          创建使用默认字符编码的 OutputStreamWriter。

 

OutputStreamWriter(OutputStream out,Charset cs)
          创建使用给定字符集的 OutputStreamWriter。

 

OutputStreamWriter(OutputStream out,CharsetEncoder enc)
          创建使用给定字符集编码器的 OutputStreamWriter。

 

OutputStreamWriter(OutputStream out,String charsetName)
          创建使用指定字符集的 OutputStreamWriter。

 

 

方法摘要

 void

close()
          关闭此流,但要先刷新它。

 void

flush()
          刷新该流的缓冲。

 String

getEncoding()
          返回此流使用的字符编码的名称。

 void

write(char[] cbuf, int off, int len)
          写入字符数组的某一部分。

 void

write(int c)
          写入单个字符。

 void

write(String str, int off, int len)
          写入字符串的某一部分。

10、什么是编码与解码?

编码:将你的文字(字符)编成电报码(字节)。即:把看得懂的编成看不懂的。

解码:解析电报码(字节)成文字(字符)。即:把看不懂的,编成看得懂的。解密

11、需求:键盘上输入一行,回车一下就转换成大写打印到控制台上。输入over,结束程序。

12、代码示例:

public class TestDemo20 {
    public static void main(String[] args) throws IOException {
       //字节流
       InputStream in = System.in;
       //将字节转化成字符的桥梁,转换流。
       InputStreamReader isr = new InputStreamReader(in);
       //字符流
       BufferedReader bufr = new BufferedReader(isr);
       OutputStream out = System.out;
       OutputStreamWriter osw = new OutputStreamWriter(out);
       BufferedWriter bufw = new BufferedWriter(osw);
       String line = null;
       while((line=bufr.readLine())!=null){
           if("over".equals(line)){
              break;
           }
           bufw.write(line.toUpperCase());
           bufw.newLine();
           bufw.flush();
       }
    }
}

13、转换方向

java要点笔记——IO流_第8张图片

14、举个例子,我从硬盘中读了一堆文件,硬盘中的文件是字节。我读到的是“你好”,这是字符。读完我想写的时候,“你好”是字符,我写到硬盘上是字节。字节→字符,字符→字节。

15、类OutputStreamWriter是FileWriter的爹。FileWriter操作文本文件,它本身读到的是字节,而出来的却是字符。那是因为字节到字符间做了转化。FileWriter用的就是他爹的方法。

16、下面这句话背过,一提到键盘录入就直接写这句话:

BufferedReader bufr=new BufferedReader(newInputStreamReader(System.in));

day22 26-IO流(转换流——需求演示)

1、需求1:将键盘录入的数据写入到一个文件中,输入over停止写入。且over不写入到文件中去。

2、代码示例1

public class TestDemo20 {
    public static void main(String[] args) throws IOException {
       BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
       BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt")));
       String line = null;
       while((line=bufr.readLine())!=null){
           if("over".equals(line)){
              break;
           }
           bufw.write(line.toUpperCase());
           bufw.newLine();
           bufw.flush();
       }
    }
}


3、需求2:将一个文本文件内容显示在控制台上。

4、代码示例2

    只需要改俩地方即可完成:

(1)、BufferedReader bufr = new BufferedReader(newInputStreamReader(new FileInputStream("a.txt")));

(2)、BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));

5、需求3:将一个文本文件中的内容复制到另一个文本文件中。

6、代码示例3

    只需要改俩地方即可完成

(1)、BufferedReader bufr = new BufferedReader(newInputStreamReader(new FileInputStream("a.txt")));

(2)、BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(new FileOutputStream("b.txt")));

day22 27-IO流(流的基本操作规律)

1、流的基本操作规律:

    之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。想要知道开发时用到那些对象。只要通过4个明确即可。

①、明确源和目的

    源:InputStream、Reader

    目的:OutputStream、writer

②、明确数据是否是纯文本数据。是不是纯文本就看内容是不是纯文字。

    源:是纯文本:Reader

       否     :InputStream

    目的:是纯文本:Writer

         否      :OutputStream

    到这里,就可以明确需求中具体要使用哪个体系。

③、明确具体的设备

    源设备:硬盘:File

           键盘:System.in

           内存:数组

           网络:Socket流

    目的设备:硬盘:File

            控制台:System.out

            内存:数组

            网络:Socket流

④、是否需要其他额外功能(各种装饰类)

    是否需要高效(缓冲区)

       是:就加上Buffered

day22 28-IO流(流的基本操作规律-需求体现1)

1、需求1:复制一个文本文件

    1)明确源和目的

       源:InputStream、Reader

       目的:OutputStream、Writer

    2)是否是纯文本

       是!源:Reader

           目的:Writer

    3)明确具体设备

       源:硬盘:File

       目的:硬盘:File

       FileReader fr= new FileReader("a.txt");

       FileWriter fw= new FileWriter("b.txt");

    4)需要额外功能吗

       需要,需要高效

       BufferedReaderbufr = new BufferedReader(new FileReader("a.txt"))

       BufferedWriterbufw = new BufferedWriter(new FileWriter("b.txt"))

2、需求2:读取键盘录入信息,并写入到一个文件中。键盘录入→文本文件

    1)明确源和目的

       源:InputStream、Reader

       目的:OutputStream、Writer

    2)是否是纯文本

       是!源:Reader

           目的:Writer

    3)明确设备

       源:键盘:System.in

       目的:硬盘:File

       InputStream in= System.in;

       FileWriter fw= new FileWriter("b.txt");

    4)需要额外功能吗

       需要。将字节流转换成字符流。因为明确的源是Reader,这样操作文本数据更便捷。所以要将已有的字节流转成字符流。InputStreamReader

       InputStreamReaderisr = new InputStreamReader(System.in);

       FileWriter fw= new FileWriter("b.txt");

       还需要功能吗?需要。高效!

       BufferedReaderbufr = new BufferedReader(new InputStreamReader(System.in))

       BufferedWriterbufw = new BufferedWriter(new FileWriter("b.txt"))

day22 29-IO流(流的基本操作规律-需求体现2)

1、需求3:将一个文本文件数据显示在控制台上。文本文件→控制台

    1)明确源和目的

       源:InputStream、Reader

       目的:OutputStream、Writer

    2)是否是纯文本

       是!源:Reader

           目的:Writer

    3)明确具体设备

       源:硬盘:File

       目的:控制台:System.out

       FileReader fr= new FileReader("a.txt");

       OutputStreamout = System.out;

    4)需要额外功能吗

       需要:转换流

       FileReader fr= new FileReader("a.txt");

       OutputStreamWriterosw = new OutputStreamWriter(System.out);

       还需要吗?需要,高效

       BufferedReaderbufr = new BufferedReader(new FileReader("a.txt"))

       BufferedWriterbufw = new BufferedWriter(new OutputStreamWriter(System.out))

2、需求4:读取键盘录入数据,显示在控制台上。键盘录入→控制台

    1)明确源和目的

       源:InputStream、Reader

       目的:OutputStream、Writer

    2)是否是纯文本

       是!源:Reader

           目的:Writer

    3)明确设备

       源:键盘:System.in

       目的:控制台:System.out

       InputStreamin = System.in;

       OutputStreamout = System.out;

    4)需要额外功能吗

       需要转换,因为前面已经明确了是Reader和Writer。所以要把字节流转换成字符流。

       InputStreamReaderisr = new InputStreamReader(System.in);

       OutputStreamWriterosw = new OutputStreamWriter(System.out);

       还需要吗?需要!高效。

       BufferedReaderbufr = new BufferedReader(new InputStreamReader(System.in));

       BufferedWriterbufw = new BufferedWriter(new OutputStreamWriter(System.out));


你可能感兴趣的:(Java要点笔记)