day31 天笔记(Io流部分)

len 长度
append 是追加

IO 流

基本概念

IO流,什么是IO?
I : Input
O : Output
通过 IO 可以完成硬盘文件的读和写。

image.png

  1. IO流的分类

有多种分类方式:

  • 一种方式是按照流的方向进行分类:

    1. 以内存作为参照物,<br /> 往内存中去,叫做输入(Input)。或者叫做读(Read)。<br /> 从内存中出来,叫做输出(Output)。或者叫做写(Write)。
  • 另一种方式是按照读取数据方式不同进行分类:

    • 有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等….

      假设文件file1.txt,采用字节流的话是这样读的:
      a中国bc张三fe
      第一次读:一个字节,正好读到’a’
      第二次读:一个字节,正好读到’中’字符的一半。
      第三次读:一个字节,正好读到’中’字符的另外一半。

    • 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取。普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取。

      假设文件file1.txt,采用字符流的话是这样读的:
      a中国bc张三fe
      第一次读:’a’字符(’a’字符在windows系统中占用1个字节。)
      第二次读:’中’字符(’中’字符在windows系统中占用2个字节。)
      注意: 空格是一个字符 Asall值是32

      综上所述:流的分类
      输入流、输出流
      字节流、字符流

Java中的IO流

  1. Java中的IO流都已经写好了,我们程序员不需要关心,我们最主要还是掌握,在java中已经提供了哪些流,每个流的特点是什么,每个流对象上的常用方法有哪些????

    java中所有的流都是在:java.io.*;下。

    java中主要还是研究:怎么new流对象 与 调用流对象的哪个方法是读、哪个方法是写。

  2. java IO 流这块有四大家族:

    四大家族的首领:
    java.io.InputStream 字节输入流
    java.io.OutputStream 字节输出流

    1. java.io.Reader 字符输入流<br /> java.io.Writer 字符输出流
    2. 四大家族的首领都是抽象类。(abstract class)
  3. 所有的流都实现了:java.io.Closeable接口

  • 都是可关闭的,都有close()方法

    1. 流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占 用)很多资源。养成好习惯,用完流一定要关闭。
  1. 所有的输出流都实现了:java.io.Flushable接口

都是可刷新的,都有flush()方法。
养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将 通道/管道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用就是清空管道。

注意:如果没有flush()可能会导致丢失数据。

  1. 注意:在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。

java.io包下需要掌握的流

  1. java.io包下需要掌握的流有16个:


    文件专属:
    java.io.FileInputStream(掌握)
    java.io.FileOutputStream(掌握)
    java.io.FileReader
    java.io.FileWriter

    转换流:(将字节流转换成字符流)
    java.io.InputStreamReader
    java.io.OutputStreamWriter

    缓冲流专属:
    java.io.BufferedReader
    java.io.BufferedWriter
    java.io.BufferedInputStream
    java.io.BufferedOutputStream

    数据流专属:
    java.io.DataInputStream
    java.io.DataOutputStream

    标准输出流:
    java.io.PrintWriter
    java.io.PrintStream(掌握)

    对象专属流:
    java.io.ObjectInputStream(掌握)
    java.io.ObjectOutputStream(掌握)

其余的了解开发的时候翻文档

File(重点)

文件专属 文件就是流

java.io.FileInputStream

构造方法:

FileInputStream(String name)
通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

常用方法:

| int read(byte[ ] b)
从该输入流读取最多 b.length个字节的数据为字节数组

int read(byte[] b, int off, int len)
从该输入流读取最多 len字节的数据为字节数组

int available():返回流当中剩余的没有读到的字节数量

long skip(long n):跳过几个字节不读 | | —- | | |

  1. 基本概念:
    1、文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
    2、字节的方式,完成输入的操作,完成读的操作(硬盘—-> 内存)

  2. Java中的文件路径:

    D:\course\JavaProjects\02-JavaSE\temp (IDEA会自动把\编程\,因为java中\表示转义)
    以下都是采用了:绝对路径的方式。
    FileInputStream fis = new FileInputStream(“D:\course\JavaProjects\02-JavaSE\temp”);
    这里的 \ 写成这个 / 也是可以的。

  3. 实例(程序有缺陷):

注意:

  1. - 读到文件末尾时 返回 -1
  2. - finally语句块当中,确保流一定关闭。关闭流的前提是:流不是空。流是null的时候没必要关闭
  3. - FileInputStream 源码中抛异常了 需要对异常进行处理
  4. - FileInputStream 创建对象时抛异常了需要对异常进行处理
  5. - read()方法源文件抛异常了 需要对异常进行处理
  6. - 关闭 close()的时候也需要 异常处理
  1. public class FileInputStreamTest01 {
  2. public static void main(String[] args) {
  3. FileInputStream fis = null;
  4. try {
  5. fis = new FileInputStream("D:/course/JavaProjects/02-JavaSE/temp");
  6. // 开始读
  7. int readData = fis.read(); // 这个方法的返回值是:读取到的“字节”本身。
  8. System.out.println(readData); //97
  9. readData = fis.read();
  10. System.out.println(readData); //98
  11. readData = fis.read();
  12. System.out.println(readData); //99
  13. // 已经读到文件的末尾了,再读的时候读取不到任何数据,返回-1.
  14. readData = fis.read();
  15. System.out.println(readData);
  16. readData = fis.read();
  17. System.out.println(readData);
  18. readData = fis.read();
  19. System.out.println(readData);
  20. } catch (FileNotFoundException e) {
  21. e.printStackTrace();
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. } finally {
  25. // 在finally语句块当中确保流一定关闭。
  26. if (fis != null) { // 避免空指针异常!
  27. // 关闭流的前提是:流不是空。流是null的时候没必要关闭。
  28. try {
  29. fis.close();
  30. } catch (IOException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }
  35. }
  36. }
  1. 对上面程序的改进

对第一个程序进行改进,循环方式。

分析以下这个程序的缺点:
一次读取一个字节byte,这样内存和硬盘交互太频繁,基本上时间/资源都耗费在交互上面了。能不能一次读取多个字节呢?可以。

  1. FileInputStream fis = null;
  2. try {
  3. fis = new FileInputStream("D:\\course\\JavaProjects\\02-JavaSE\\temp");
  4. /*while(true) {
  5. int readData = fis.read();
  6. if(readData == -1) {
  7. break;
  8. }
  9. System.out.println(readData);
  10. }*/
  11. // 改造while循环
  12. int readData = 0;
  13. while((readData = fis.read()) != -1){
  14. System.out.println(readData);
  15. }
  16. } catch (FileNotFoundException e) {
  17. e.printStackTrace();
  18. } catch (IOException e) {
  19. e.printStackTrace();
  20. } finally {
  21. if (fis != null) {
  22. try {
  23. fis.close();
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }

int read(byte[ ] b)


read (byte[] b, int off, int len)

  • 往byte[]数组当中读:一次最多读取 b.length 个字节,减少硬盘和内存的交互,提高程序的执行效率。

  • 将 byte 数组转换成String类型的字符串: 调用: String 类 的构造方法 传入byte数组 转换为 String类型

  • 语法格式:

String(Byte,0,length-1)

  1. FileInputStream fis = null;
  2. try {
  3. // 开始读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节。
  4. byte[] bytes = new byte[4]; // 准备一个4个长度的byte数组,一次最多读取4个字节。
  5. // 这个方法的返回值是:读取到的字节数量。(不是字节本身)
  6. int readCount = fis.read(bytes);
  7. System.out.println(readCount); // 第一次读到了4个字节。
  8. // 将字节数组全部转换成字符串
  9. //System.out.println(new String(bytes)); // abcd
  10. // 不应该全部都转换,应该是读取了多少个字节,转换多少个。
  11. System.out.println(new String(bytes,0, readCount));
  12. readCount = fis.read(bytes); // 第二次只能读取到2个字节。
  13. System.out.println(readCount); // 2
  14. // 将字节数组全部转换成字符串
  15. //System.out.println(new String(bytes)); // efcd
  16. // 不应该全部都转换,应该是读取了多少个字节,转换多少个
  17. //不这样处理的话输出efcd
  18. System.out.println(new String(bytes,0, readCount));
  19. readCount = fis.read(bytes); // 1个字节都没有读取到返回-1
  20. System.out.println(readCount); // -1
  21. } catch (FileNotFoundException e) {
  22. e.printStackTrace();
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. } finally {
  26. if (fis != null) {
  27. try {
  28. fis.close();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }

文件里面的内容:abcdef

下面这个需要掌握

  1. public class FileInputStreamTest04 {
  2. public static void main(String[] args) {
  3. FileInputStream fis = null;
  4. try {
  5. fis = new FileInputStream("chapter23/src/tempfile3");
  6. // 准备一个byte数组
  7. byte[] bytes = new byte[4];
  8. /*while(true){
  9. int readCount = fis.read(bytes);
  10. if(readCount == -1){
  11. break;
  12. }
  13. // 把byte数组转换成字符串,读到多少个转换多少个。
  14. System.out.print(new String(bytes, 0, readCount));
  15. }*/
  16. int readCount = 0;
  17. while((readCount = fis.read(bytes)) != -1) {
  18. System.out.print(new String(bytes, 0, readCount));
  19. }
  20. } catch (FileNotFoundException e) {
  21. e.printStackTrace();
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. } finally {
  25. if (fis != null) {
  26. try {
  27. fis.close();
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. }
  34. }

IDEA中的路径

相对路径的话呢? 相对路径一定是从当前所在的位置作为起点开始找!
IDEA默认的当前路径是哪里? 工程Project的根就是IDEA的默认当前路径。
如果该路径下 没有此文件会报错

  1. fis = new FileInputStream("tempfile3");
  2. //fis = new FileInputStream("chapter23/tempfile2");
  3. //fis = new FileInputStream("chapter23/src/tempfile3");
  4. fis = new FileInputStream("chapter23/src/com/bjpowernode/java/io/tempfile4");

FileInputStream类的其它常用方法


int available(): 返回 流 当中剩余的没有读到的字节数量

  1. long skip(long n): 跳过几个字节不读
  1. 列子:

    1. public class FileInputStreamTest05 {
    2. public static void main(String[] args) {
    3. FileInputStream fis = null;
    4. try {
    5. fis = new FileInputStream("tempfile");
    6. System.out.println("总字节数量:" + fis.available());
    7. // 读1个字节
    8. //int readByte = fis.read();
    9. // 还剩下可以读的字节数量是:5
    10. //System.out.println("剩下多少个字节没有读:" + fis.available());
    11. // 这个方法有什么用?
    12. //byte[] bytes = new byte[fis.available()]; // 这种方式不太适合太大的文件,因为byte[]数组不能太大。
    13. // 不需要循环了。
    14. // 直接读一次就行了。
    15. //int readCount = fis.read(bytes); // 6
    16. //System.out.println(new String(bytes)); // abcdef
    17. // skip跳过几个字节不读取,这个方法也可能以后会用!
    18. fis.skip(3);
    19. System.out.println(fis.read()); //100
    20. } catch (FileNotFoundException e) {
    21. e.printStackTrace();
    22. } catch (IOException e) {
    23. e.printStackTrace();
    24. } finally {
    25. if (fis != null) {
    26. try {
    27. fis.close();
    28. } catch (IOException e) {
    29. e.printStackTrace();
    30. }
    31. }
    32. }
    33. }
    34. }

FileOutputStream

文件的写入 内存———> 硬盘
文件字节输出流,负责写。

  1. 构造方法:

FileOutputStream(String name)

FileOutputStream(String name, true) 这个构造方法表示在文件的末尾追加

  1. 案例:

注意:

  1. - 文件不存在的时候会自动新建
  2. - 写完之后一定要刷新
  3. - fos = new FileOutputStream("chapter23/src/tempfile3");

这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入。

  1. - fos = new FileOutputStream("chapter23/src/tempfile3", true);

以追加的方式在文件末尾写入。不会清空原文件内容。
这里的true 表示的含义是 是否以文件追加的方式 在文件末尾写入
不加 true 这个默认参数的话是 默认将文件清空的

  • 将String类型转换为数组:

    • String类型的对象 . getBytes();

      1. public class FileOutputStreamTest01 {
      2. public static void main(String[] args) {
      3. FileOutputStream fos = null;
      4. try {
      5. // myfile文件不存在的时候会自动新建!
      6. // 这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入。
      7. //fos = new FileOutputStream("myfile");
      8. //fos = new FileOutputStream("chapter23/src/tempfile3");
      9. // 以追加的方式在文件末尾写入。不会清空原文件内容。
      10. fos = new FileOutputStream("chapter23/src/tempfile3", true);
      11. // 开始写。
      12. byte[] bytes = {97, 98, 99, 100};
      13. // 将byte数组全部写出!
      14. fos.write(bytes); // abcd
      15. // 将byte数组的一部分写出!
      16. fos.write(bytes, 0, 2); // 再写出ab
      17. // 字符串
      18. String s = "我是一个中国人,我骄傲!!!";
      19. // 将字符串转换成byte数组。
      20. byte[] bs = s.getBytes();
      21. // 写
      22. fos.write(bs);
      23. // 写完之后,最后一定要刷新
      24. fos.flush();
      25. } catch (FileNotFoundException e) {
      26. e.printStackTrace();
      27. } catch (IOException e) {
      28. e.printStackTrace();
      29. } finally {
      30. if (fos != null) {
      31. try {
      32. fos.close();
      33. } catch (IOException e) {
      34. e.printStackTrace();
      35. }
      36. }
      37. }
      38. }
      39. }

文件的复制

  1. 文件的复制原理

  1. 案例:

FileReadr

能用记事本编辑的都是普通文本文件,普通文本文件和后缀无关
字节流是 Byte 数组 字符流是 char 数组

copy1
copy2

缓冲专属

BufferedRead

1.基本概念
带有缓冲区的字符输入流。
使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。

  1. 构造方法与其它流不同

语法格式:
BufferedReader( Reader in )

说明:
看Api得出的:
Reader 是一个抽象类
FileReader类是Reader类的子类 它的父类是InputStreamReader类
InputStreamReader类的父类是Reader

  1. 特有的方法:
  • readerLine()

这个方法读到文件末尾结束
作用:读取一个文本行 (读一行) 不带换行符

  1. 案例

    • 说明:

      • 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
      • 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。
    • 看源代码得出的:

      1. - BufferedReader中有一个实例变量 Reader in
      2. - Reader in 就是一个节点,in 是一个属性,通过构造方法进行赋值
      3. - bufferedReader就是一个包装
      4. - 传入的节点的原理:
      5. - 将传入的节点流赋值给 Reader in 这个属性
      6. - bufferReader这个流里面有一个close(),这个close ()里面有一个in在调用close(),所以当BufferedReader 去关闭的时候里面的流会自动关闭
      • 得出的结论:

        • 对一个包装流来说,只需要关闭最外层的就行,里面的节点流会自动关闭。 ```java public class BufferedReaderTest01 { public static void main(String[] args) throws Exception{

        FileReader reader = new FileReader(“Copy02.java”); // 当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流。 // 外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。 // 像当前这个程序来说:FileReader就是一个节点流。BufferedReader就是包装流/处理流。 BufferedReader br = new BufferedReader(reader);

        // 读一行 /*String firstLine = br.readLine(); System.out.println(firstLine);

        String secondLine = br.readLine(); System.out.println(secondLine);

        String line3 = br.readLine(); System.out.println(line3);*/

        // br.readLine()方法读取一个文本行,但不带换行符。 String s = null; while((s = br.readLine()) != null){

        1. System.out.print(s);

        }

        // 关闭流 // 对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭。(可以看源代码。) br.close(); } } ```

转换流

BufferedReader02
通过对应的构造方法将字节流

数据专属流

标准输出流

println
logger
日志工具

File类

  1. 基本概念
  • File类和四大家族没有关系,所以File类不能完成文件的读和写。

  • File对象代表什么?
    文件和目录路径名的抽象表示形式。
    C:\Drivers 这是一个File对象
    C:\Drivers\Lan\Realtek\Readme.txt 也是File对象。
    一个File对象有可能对应的是目录,也可能是文件。
    File只是一个路径名的抽象表示形式。

  • 需要掌握File类中常用的方法

filetest02

拷贝目录

对象专属流