JavaSE进阶-06-IO流

1.什么是IO流?

答:文件的输入和输出
  将文件放入内存的过程叫输入(Input)也称为读(Read),
输入过程产生的数据的流动叫输入流(InputStream)。

  将文件从内存 存放到硬盘的过程叫输出(Output)也称为写(Write),
输出过程产生的数据的流动叫输出流(OutputStream)。

通过IO可以完成硬盘文件的读和写。

2.IO流的分类

2.1按照流的方向进行分类:

以内存作为参照物
 往内存中去,叫做输入(Input),或者叫做读(Read)
 从内存出来,叫做输出(Output),或者叫做写(Write)

2.2按照读取数据方式不同:

 按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型都可以读取。包括:文本文件、图片、音频文件、视频文件......
这种流叫字节流
  假设文件filel.txt,采用字节流的话是这样读的:
a中国bc张三fe
第一次读:一个字节,正好读到‘a’
第二次读:一个字节,正好读到‘中’字符的一半
第三次读:一个字节,正好读到‘中’字符的另一半

 按照字符的方式读取数据,一次读取一个字符。这种流是为了方便读取普通的文本文件而存在的,不能读取:图片、音频、视频等文件。只能读取纯文本文件。(work文件有格式,不是普通文件.txt,故word文件也无法读取。注意能用记事本编辑的都是文本文件
这种流叫字符流
  假设文件filel.txt,采用字节流的话是这样读的:
a中国bc张三fe
第一次读:一个字符,正好读到‘a’
第二次读:一个字符,正好读到‘中’字符
第三次读:一个字符,正好读到‘国’字符

‘a’英文字母,在Windows操作系统中占1个字节;但是‘a’字符在java中占用2个字节。
‘中’字符在Windows系统中占用2个字节。

综上所述

流的分类:
输入流、输出流
字节流、字符流

3.Java IO流

java中所有流都是在java.io.*
主要研究如何new流对象,调用流对象的哪个方法是读,哪个方法是写。

Java IO四大家族(都是抽象类)
java.io.InputStream:字节输入流
java.io.OutputStream:字节输出流
java.io.Reader:字符输入流
java.io.Writer:字符输出流
在java中只要类名以Stream结尾都是字节流,以Reader/Writer结尾的都是字符流

所有流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。
养成好习惯:流是内存和硬盘之间的通道,用完后一定要关闭,不然会占用很多内存。

所有输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。
养成好习惯:输出流在最终输出之后,一定能更要flush()刷新一下。(表示将通道/管道当中剩余未输出的数据强行输出完,即清空管道。)

4.Java 需要掌握的16个IO流

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

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

缓冲流
java.io.BufferedInputStream
java.io.BufferedOutputStream
java.io.BufferedReader
java.io.BufferedWriter

数据流
java.io.DataInputStream
java.io.DataOutputStream

标准输出流
java.io.PrinfWriter
java.io.PrintStream掌握

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

文件专属流

4.1 java.io.FileInputStream(重点掌握)

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

4.1.1 read()
package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest01 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        try {
            //创建文件字节流输入流对象
            //文件路径:G:\大4上学期\实习\JavaSE\temp(IDEA会自动把\变成\\,因为java中\表示转译,把\\替换成/也可以。)
            fileInputStream=new FileInputStream("G:\\大4上学期\\实习\\JavaSE\\temp");

            //开始读
            int read = fileInputStream.read();//这个方法的返回值是:读取到的“字节”本身
            System.out.println(read);//97

            read = fileInputStream.read();//98
            System.out.println(read);

            read = fileInputStream.read();//99
            System.out.println(read);

            read = fileInputStream.read();//100
            System.out.println(read);

            read = fileInputStream.read();//101
            System.out.println(read);

            read = fileInputStream.read();//102
            System.out.println(read);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭字节数入流对象
            if (fileInputStream != null) {
                //关闭流的前提是:流不是空,流是null没必要关闭
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}


问题:该例中使用read(),存在代码冗余,可采用循环的方式读取:

package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest02 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;

        try {
            //创建字节输出流对象
            fileInputStream=new FileInputStream("G:\\大4上学期\\实习\\JavaSE\\temp");
            //读
            /*while (true){
                int read=fileInputStream.read();
                if (read == -1) {
                    break;
                }
                System.out.println(read);
            }*/
            //改造while循环
            int read=0;
            while((read=fileInputStream.read()) != -1){
                System.out.println(read);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放字节输出流对象
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

4.1.2 read(byte[] b)

问题read()使用循环读取后,存在效率低的问题。一次才读一个字节,硬盘与内存交互太频繁。改进方案:使用read(byte[] b)


将数组转换成String

注意
 开始读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节
 这个方法的返回值:读到的字节数量,不是字节本身。

package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
int read(byte[] b)
    一次最多读取b.length个字节。
    减少硬盘和内存的交互,提高程序的执行效率。
*/
public class FileInputStreamTest03 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        try {
            //创建字节输出流对象
            //使用相对路径,一定是当前所在的位置作为起点开始找!
            //IDEA默认的当前路径:工程Project的根
            fileInputStream=new FileInputStream("temp");
            //开始读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节
            byte[] bytes=new byte[4];
            //这个方法的返回值:读到的字节数量,不是字节本身。
            int read = fileInputStream.read(bytes);//第一次读到了4个字节
            System.out.println(new String(bytes,0,read));//abcd

            read = fileInputStream.read(bytes);//第二次读到了2个字节
            System.out.println(new String(bytes,0,read));//ef

            read = fileInputStream.read(bytes);//第三次读到了0个字节
            System.out.println(read);//返回-1。

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

注意
 使用相对路径,一定是当前所在的位置作为起点开始找!
 IDEA默认的当前路径:工程Project的根



问题:该例中使用String(byte[] bytes, int offset, int length),既减少了硬盘和内存的交互,也可以读多少就转多少,但未采用循环的方式读取。改进后:

package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest04 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        try {
            //声明字节输出流对象
            fileInputStream=new FileInputStream("temp");
            //准备一个byte数组
            byte[] bytes=new byte[4];
            int read=0;
            while ((read = fileInputStream.read(bytes)) != -1){
                System.out.print(new String(bytes,0,read));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}



FileInputStream类的其他常用方法:

4.1.3 int available():

返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
 即返回流当中剩余的没有读到的字节数量。
作用:创建数组时使用,不再需要循环。但不适合大文件,因为byte数组不能太大。

package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest05 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        try {
            fileInputStream=new FileInputStream("temp");
            System.out.println("剩余未读字节:"+fileInputStream.available());
            //直接获得剩余未读字节数,不再需要循环了
            byte[] bytes=new byte[fileInputStream.available()];
            int read = fileInputStream.read(bytes);
            System.out.println(new String(bytes,0,read));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


4.1.4 long skip(long n)

从输入流中跳过并丢弃 n个字节的数据
 即跳过几个字节不读。

package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest05 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        try {
            fileInputStream=new FileInputStream("temp");
            fileInputStream.skip(42);
            System.out.println("剩余未读字节:"+fileInputStream.available());
            //直接获得剩余未读字节数,不再需要循环了
            byte[] bytes=new byte[fileInputStream.available()];
            int read = fileInputStream.read(bytes);
            System.out.println(new String(bytes,0,read));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


4.2 java.io.FileOutputStream(重点掌握

 1.文件字节输出流。
 2.字节的方式,完成输出的操作,完成写的操作(内存-->硬盘)

4.2.1 write(byte[] b)

 将 b.length 个字节从指定 byte 数组写入此文件输出流中。 |
注意:文件不存在会自动新建,存在则把原文件清空再写。

package com.bjpowernode.java.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream fileOutputStream=null;
        try {
            fileOutputStream=new FileOutputStream("myfile");
            //开始写
            byte[] bytes=new byte[]{97,98,99,100};
            fileOutputStream.write(bytes);
            //写完要刷新
            fileOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4.2.2 write(byte[] b,int off,int len)

 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
注意:文件不存在会自动新建,存在则把原文件清空再写。

package com.bjpowernode.java.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream fileOutputStream=null;
        try {
            fileOutputStream=new FileOutputStream("myfile");
            //开始写
            byte[] bytes=new byte[]{97,98,99,100};
            fileOutputStream.write(bytes,0,2);
            //写完要刷新
            fileOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


4.2.3 FileOutputStream(String name, boolean append)

 创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。创建一个新 FileDescriptor 对象来表示此文件连接。
注意:这个方法可以以追加的方式在文件末尾写入,不会清空原文件内容。

package com.bjpowernode.java.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream fileOutputStream=null;
        try {
            //以追加的方式写,不会清空源文件内容
            fileOutputStream=new FileOutputStream("myfile",true);
            //开始写
            byte[] bytes=new byte[]{97,98,99,100};
            fileOutputStream.write(bytes);
            //写完要刷新
            fileOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

写字符串
要点:
 1.定义一个字符串。String s= “内容”;
 2.将字符串转成byte数组。s.getBytes()

package com.bjpowernode.java.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream fileOutputStream=null;
        try {
            fileOutputStream=new FileOutputStream("myfile",true);
            String s="今天天气真不错!";
            //将字符串转换成byte数组
            byte[] bytes = s.getBytes();
            //开始写
            fileOutputStream.write(bytes);
            //写完要刷新
            fileOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

文件拷贝
使用FileInputStream+FileOutputStream完成文件的拷贝。
拷贝的过程是一边读一边写。
使用以上字节流可拷贝任意类型的文件。

文件复制流程图

package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/*
使用FileInputStream+FileOutputStream完成文件的拷贝。
拷贝的过程是一边读一边写。
使用以上字节流可拷贝任意类型的文件。
*/
public class Copy01 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;

        try {
            //创建一个字节输入流对象
            fileInputStream=new FileInputStream("temp");
            //创建一个字节输出流对象
            fileOutputStream=new FileOutputStream("tempCopy");

            //一边读一边写
            byte[] bytes=new byte[1024 * 1024];// 一次最多拷贝1MB
            int read=0;
            //while条件里开始读
            while ((read=fileInputStream.read(bytes)) != -1){
                //while方法体内写
                fileOutputStream.write(bytes,0,read);
            }

            //输出流最后要刷新
            fileOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //分开try,一起try时,其中一个出异常会影响另一个流的关闭。
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}


4.3 java.io.FileReader

 文件字符输入流,只能读取普通文本。
 读取文本内容时,比较方便快捷。

package com.bjpowernode.java.io;

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

public class FileReaderTest {
    public static void main(String[] args) {
        FileReader fileReader=null;
        try {
            //创建字符输入流
            fileReader=new FileReader("temp");
            //开始读
            char[] chars=new char[4];//一次读取4个字符
            int readCount=0;
            while ((readCount=fileReader.read(chars))!= -1){
                System.out.print(new String(chars,0,readCount));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


4.4 java.io.FileOutputStream

 文件字符输出流,写。
 只能输出普通文本。

package com.bjpowernode.java.io;

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

/*
    文件字符输出流,写
    只能输出普通文本。
*/
public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter fileWriter=null;
        try {
            //创建字符输出流对象
            fileWriter=new FileWriter("temp",true);
            //开始写
            char[] chars={'我','爱','你','中','国'};
            fileWriter.write(chars);//可写数组、字符、字符串
            fileWriter.write(chars,2,3);
            fileWriter.write("\n");//换行符
            fileWriter.write('善');//可写数组、字符、字符串
            fileWriter.write("我是一个java软件工程师");//可写数组、字符、字符串
            //刷新
            fileWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


复制文件
 使用FileReader FileWriter进行拷贝的话,只能拷贝“普通文本”文件。

package com.bjpowernode.java.io;

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

/*
使用FileReader FileWriter进行拷贝的话,只能拷贝“普通文本”文件。
*/
public class Copy02 {
    public static void main(String[] args) {
        FileReader fileReader=null;
        FileWriter fileWriter=null;

        try {
            //创建字符输入流对象,负责读的
            fileReader=new FileReader("temp");
            //创建字符输出流对象,负责写的
            fileWriter=new FileWriter("tempCopy2");
            //一边读一边写
            char[] chars=new char[1024 * 512];//每次最多读1MB
            int readCount=0;
            while ((readCount=fileReader.read(chars))!= -1){
                fileWriter.write(chars);
            }
            //刷新
            fileWriter.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


缓冲流

4.5 java.io.BufferedReader:

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

注意:
 1. 当一个流的构造方法中需要传一个流时,这个被传进来的流被称为“节点流
 2. 外部负责包装的流,叫做“包装流”或“处理流
 3. 对于包装流来说,只需要关闭最外层包装流就行,里面的节点流会自动关闭。

利用readLine方法循环遍历
package com.bjpowernode.java.io;

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

/*
BufferedReader
    带有缓冲区的字符输入流
    使用这个流的时候不需要自定义char数组或byte数组,自带缓冲。
*/
public class BufferedReaderTest01 {
    public static void main(String[] args) throws Exception{
        FileReader fr=new FileReader("temp");
        //当一个流的构造方法中需要传一个流时,这个被传进来的流被称为“节点流”
        //外部负责包装的流,叫做“包装流”或“处理流”
        //像当前这个程序来说:节点流是FileReader,包装流是BufferedReader
        BufferedReader br=new BufferedReader(fr);

        //利用readLine循环读
        String firstLine2=null;
        while ( (firstLine2=br.readLine()) != null ){
            System.out.println(firstLine2);
        }

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

4.6 java.io.BufferedWriter:

 1.带有缓冲区的字符输出流
 2.使用这个流的时候不需要自定义char数组或byte数组,自带缓冲。

package com.bjpowernode.java.io;

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

public class BufferedWriterTest {
    public static void main(String[] args) {
        try {
            //创建带有缓冲区的字符输出流对象
            BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("temp"));
            //写
            bufferedWriter.write("hello world!");
            bufferedWriter.write("\n");
            bufferedWriter.write("hello kitty!");
            //刷新
            bufferedWriter.flush();
            //关闭
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


转换流

4.7 java.io.InputStreamReader

package com.bjpowernode.java.io;

import java.io.*;

public class BufferedReaderTest02 {
    public static void main(String[] args) {
        try {
            //创建字节输入流对象
            FileInputStream in=new FileInputStream("temp");

            //使用转换流将字节流转换成字符流再传入BufferedReader中。
            //这里in是“节点流”,reader是“包装流”
            InputStreamReader reader=new InputStreamReader(in);

            //因为BufferedReader只能传字符流对象,不能传字节流对象,故需要用转换流先转换一下。
            //这里reader是“节点流”,br是“包装流”
            BufferedReader br=new BufferedReader(reader);

            //开始读
            String line=null;
            while( (line = br.readLine()) != null){
                System.out.println(line);
            }

            //关闭最外层
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
简化代码后
package com.bjpowernode.java.io;

import java.io.*;

public class BufferedReaderTest02 {
    public static void main(String[] args) {
        try {
        
            BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("temp")));

            //开始读
            String line=null;
            while( (line = br.readLine()) != null){
                System.out.println(line);
            }

            //关闭最外层
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.8 java.io.OutputStreamWriter

package com.bjpowernode.java.io;

import java.io.*;

public class BufferedWriterTest {
    public static void main(String[] args) {
        try {
            //先创建字节输出流,再使用转换流创建带有缓冲区的字符输出流对象
            BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("temp",true)));
            //写
            bufferedWriter.write("大家好!");
            bufferedWriter.write("\n");
            bufferedWriter.write("新年快乐!");
            //刷新
            bufferedWriter.flush();
            //关闭
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


数据流

4.9 java.io.DataInputStream

 DataOutputStream写的文件,只能使用DataInputStream去读。
 注意:读顺序需要和写的顺序一致,才能正常取出数据。

package com.bjpowernode.java.io;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
DataInputStream:数据字节输入流
DataOutputStream写的文件,只能使用DataInputStream去读。并且读顺序需要和写的顺序一致,才能正常取出数据。
*/
public class DataInputStreamTest01 {
    public static void main(String[] args) {
        DataInputStream dataInputStream=null;
        try {
            //创建数据专属的字节输入流对象
            dataInputStream=new DataInputStream(new FileInputStream("temp"));
            //读
            byte b=dataInputStream.readByte();
            short s=dataInputStream.readShort();
            int i =dataInputStream.readInt();
            long l=dataInputStream.readLong();
            float f=dataInputStream.readFloat();
            double d =dataInputStream.readDouble();
            boolean sex =dataInputStream.readBoolean();
            char c=dataInputStream.readChar();

            System.out.println(b);
            System.out.println(s);
            System.out.println(i);
            System.out.println(l);
            System.out.println(f);
            System.out.println(d);
            System.out.println(sex);
            System.out.println(c);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dataInputStream != null) {
                try {
                    dataInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4.10 java.io.DataOutputStream

  这个流可以将数据连同数据的类型一并写入文件
  注意:这个文件不是普通文本文档。(用记事本打不开,要去数据得用DataInputStream)

package com.bjpowernode.java.io;

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/*
 java.io.DataInputStream:数据专属的流
 这个流可以将数据连同数据的类型一并写入文件
 注意:这个文件不是普通文本文档。(用记事本打不开)
*/
public class DataOutputStreamTest {
    public static void main(String[] args) {
        DataOutputStream dos=null;
        try {
            //创建数据专属的字节输出流
            dos=new DataOutputStream(new FileOutputStream("temp"));
            //写数据
            byte b=100;
            short s=200;
            int i =300;
            long l=400L;
            float f=3.0F;
            double d =3.14;
            boolean sex =false;
            char c='a';
            //把数据以及数据的类型一并写入到文件当中
            dos.writeByte(b);
            dos.writeShort(s);
            dos.writeInt(i);
            dos.writeLong(l);
            dos.writeFloat(f);
            dos.writeDouble(d);
            dos.writeBoolean(sex);
            dos.writeChar(c);
            //刷新
            dos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭最外层
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


标准输出流

4.11 java.io.PrinfWriter

4.12 java.io.PrintStream(重点掌握)

 标准的字节输出流,默认输出到控制台。
 标准输出流不需要手动close()关闭。

package com.bjpowernode.java.io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class PrintStreamTest {
    public static void main(String[] args) throws Exception {
        //联合起来写
        System.out.println("hello world!");

        //分开写
        PrintStream ps=System.out;
        ps.print("hello zhangsan");

        //标准输出流不再指向控制台,指向temp文件
        PrintStream printStream=new PrintStream(new FileOutputStream("tempCopy"));
        //修改输出方向,将输出方向修改到“temp”文件
        System.setOut(printStream);
        //再输出
        System.out.println("hello world!");
        System.out.println("hello kitty");
        System.out.println("hello zhangsan");

    }
}




日志工具

package com.bjpowernode.java.io;

import javax.xml.crypto.Data;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
日志工具
*/
public class LogUtil {
    /*
    记录日志的方法
    */
    public static void  log(String msg){
        try {
            //指向一个日志文件
            PrintStream out = new PrintStream(new FileOutputStream("log.txt",true));
            //改变输出方向
            System.setOut(out);
            //日期当前时间
            Date nowTime=new Date();
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String strTime =sdf.format(nowTime);

            System.out.println(strTime+":"+msg);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
package com.bjpowernode.java.io;

public class logTest {
    public static void main(String[] args) {
        //测试工具类是否好用
        LogUtil.log("调用了System类的gc()方法,建议启动垃圾回收");
        LogUtil.log("调用了UserService的doSome()方法");
        LogUtil.log("用户尝试进行登录,验证失败");
        LogUtil.log("我非常喜欢这个记录日志的工具哦!");
    }
}


对象专属流

序列化和反序列化

4.13java.io.ObjectInputStream(重点掌握)

序列化:

package com.bjpowernode.java.bean;

public class Student {
    private int no;
    private String name;
    //省略构造方法、setter和getter方法、toString方法
package com.bjpowernode.java.io;

import com.bjpowernode.java.bean.Student;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamTest01 {
    public static void main(String[] args) throws Exception{
        //创建java对象
        Student s=new Student(1111,"zhangsan");
        //序列化
        ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("student"));
        //序列化对象
        oos.writeObject(s);
        //刷新
        oos.flush();
        //关闭
        oos.close();
    }
}
不支持序列化

分析:直接创建一个Student类,不支持序列化。Student类需要继承Serializable可序列化接口

package com.bjpowernode.java.bean;

public class Student implements Serializable  {
    private int no;
    private String name;
    //省略构造方法、setter和getter方法、toString方法
序列化成功

总结(重要):参与序列化和反序列化的对象需要实现Serializable可序列化接口
(Serializable接口什么代码都没有,但它起标识的作用。java虚拟机看到这个类实现了这个接口,会为该类自动生成一个序列化版本号。)

序列化版本号:
 Java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号。

Java语言中通过什么机制来区分类的?
 第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类;
 第二:如果类名一样,靠序列化版本号进行区分。

好处
 因为类只要实现了Serializable接口,就能自动生成序列化版本号,Java虚拟机可以根据序列化版本号的不同,区分类。

缺陷
 一个类在序列化后,会生成一个序列化版本号。若未来这个类有修改,会生成一个新的序列化版本号。虽然从业务逻辑角度上还是同一个类,但前后序列化版本号不一致,Java虚拟机会认为是两个类。
 一旦代码确定之后,不能进行后续的修改。因为只要修改必然会重新编译,此时会生成全新的序列化版本号,Java虚拟机会认为这是一个全新的类。

总结
 凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号(即不使用自动生成序列化版本号)。
例如:private static final long seralVersionUID =11;

IDEA快捷生成序列化版本号:

IDEA快捷生成序列化版本号1
IDEA快捷生成序列化版本号2
IDEA快捷生成序列化版本号3
IDEA快捷生成序列化版本号4

一次性序列化多个对象:
将对象放到集合中,序列化集合
直接存储多个对象,第二个就会报错

package com.bjpowernode.java.io;

import com.bjpowernode.java.bean.User;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
//参与序列化的ArrayList集合以及集合中的元素User都需要实现java.io.Serializable接口
public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception{
        //准备一个List集合
        List<User> userList=new ArrayList<>();
        userList.add(new User(1,"zhangsan"));
        userList.add(new User(2,"lisi"));
        userList.add(new User(3,"wangwu"));
        //序列化
        ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("users"));
        //一次序列化一个集合对象,这个集合对象中存放了很多其他对象
        oos.writeObject(userList);
        //关闭
        oos.close();

    }
}
package com.bjpowernode.java.io;

import com.bjpowernode.java.bean.User;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;

/*
反序列化集合
*/
public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception{
        //反序列化
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("users"));
        //反序列化对象
        List<User> userList = (List<User>) ois.readObject();
        for (User user:userList
             ) {
            System.out.println(user);
        }
        //关闭
        ois.close();
    }
}
序列化集合



若想指定某个属性不参与序列化,使用transient关键字修饰指定属性。👇

package com.bjpowernode.java.bean;

import java.io.Serializable;

public class User implements Serializable {
    private int no;
    //transient关键字标识游离的,不参与序列化
    private transient String name;
    //省略setter和getter、toString、构造方法。
}
transient关键字


4.14 java.io.ObjectOutputStream(重点掌握)

反序列化

package com.bjpowernode.java.io;

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class ObjectInputStreamTest01 {
    public static void main(String[] args) throws Exception{
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("student"));
        //开始反序列化,读
        Object o = objectInputStream.readObject();
        //反序列化回来是一个学生对象,所以会调用学生对象的toString方法
        System.out.println(o);
        //关闭
        objectInputStream.close();
    }
}
反序列化结果


4.15 java.io.File类

 1.File类和四大家族没有关系,所以FIle类不能完成文件的读和写
 2.File对象代表什么?
  :文件和目录路径名的抽象表示形式
  C:\fitnesse-src-20161106 是一个File对象
  C:\fitnesse-src-20161106\gradlew.bat 也是File对象
  一个File对象有可能对应的是目录,也可能是文件。
  3.需要掌握File类的常用方法
  exists():测试此抽象路径名表示的文件或目录是否存在。
  createNewFile():当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。
  mkdir():创建此抽象路径名指定的目录。
  mkdirs():创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
  getParent():返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。(返回String类型)
  getParentFile():返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。(返回File类型)
  getAbsolutePath():返回此抽象路径名的绝对路径名字符串。
  getName():返回由此抽象路径名表示的文件或目录的名称。
  isDirectory():测试此抽象路径名表示的文件是否是一个目录。
  isFile():测试此抽象路径名表示的文件是否是一个标准文件。
  lastModified():返回此抽象路径名表示的文件最后一次被修改的时间。(返回值是long类型,表示从1970年到现在的总毫秒数。)
  length():返回由此抽象路径名表示的文件的长度(即文件的大小)。
  length():返回由此抽象路径名表示的文件的长度(即文件的大小)。
  listFiles():返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。

package com.bjpowernode.java.io;

import java.io.File;
import java.io.IOException;

public class FileTest01 {
    public static void main(String[] args) throws Exception {

        /*File file=new File(("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\file"));
        //判断文件是否存在
        System.out.println(file.exists());*/

        /*//如果G:\大4上学期\实习\JavaSE\chapter23\src\com\bjpowernode\java\io\file不存在,则以文件的形式创建出来
        if (!file.exists()) {
            file.createNewFile();
        }*/

       /* //如果G:\大4上学期\实习\JavaSE\chapter23\src\com\bjpowernode\java\io\file不存在,则以目录的形式创建出来
        if (!file.exists()) {
            file.mkdir();
        }*/

        /*File file2=new File(("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\file\\a\\b\\c\\d"));
        if (!file2.exists()) {
            //以多重目录的形式新建
            file2.mkdirs();
        }*/

        File file3=new File(("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\file"));
        //获取文件的父路径
        String parentPath=file3.getPath();
        System.out.println(parentPath);
        File parentFile=file3.getParentFile();
        System.out.println("获取绝对路劲:"+parentFile.getAbsolutePath());

        File file4=new File("temp");
        System.out.println("获取绝对路径:"+file4.getAbsolutePath());
    }
}
package com.bjpowernode.java.io;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
File类的常用方法
*/
public class FileTest02 {
    public static void main(String[] args) {
        File f1=new File("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\BufferedReaderTest01.java");
        //获取文件名
        System.out.println("文件名:"+f1.getName());
        //判断是是否是一个目录
        System.out.println(f1.isDirectory());//false
        //判断是否是一个文件
        System.out.println(f1.isFile());//true

        //获取文件最后一次修改时间
        long haoMiao=f1.lastModified();//这个毫秒是从1970年到现在的总毫秒数。
        Date time=new Date(haoMiao);
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String strTime=sdf.format(time);
        System.out.println(strTime);

        //获取文件大小
        System.out.println(f1.length());//1054
    }
}
package com.bjpowernode.java.io;

import java.io.File;

/*
File中的listFIles方法
*/
public class FileTest03 {
    public static void main(String[] args) {
        //File[] listFiles()
        //获取当前目录下所有的子文件
        File f=new File("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io");
        File[] files = f.listFiles();
        //foreach
        for (File file :files) {
            System.out.println(file.getAbsolutePath());
            System.out.println(file.getName());
        }
    }
}


目录拷贝(非常具有代表性)

题目:拷贝一个目录到一个地方

解题思路:
 递归
 FileInputStream
 FileOutputStream
 字符串拼接

 boolean endsWith(String suffix):
测试此字符串是否以指定的后缀结束。

package com.bjpowernode.java.io;

import java.io.File;
/*
测试:拷贝一个目录到一个地方
*/
public class work {
    public static void main(String[] args) {
        CopyUtil copyUtil=new CopyUtil();
        //指定拷贝源
        File srcFile=new File("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com");
        //拷贝目标
        File destFile=new File("G:\\a\\");
        //调用方法拷贝
        copyUtil.copy(srcFile,destFile);
    }
}
package com.bjpowernode.java.io;

import java.io.*;
/*
inPath:拷贝源
outPatch: 拷贝目标
*/
public class CopyUtil {
    private static FileInputStream fi=null;
    private static FileOutputStream fo=null;

    public void copy(File inPath, File outPath) {
        if (inPath.isFile()){
            //是文件的时候需要拷贝,一边读一边写
            try {
                //读文件
                fi=new FileInputStream(inPath);
                //写文件
                String path=(outPath.getAbsolutePath().endsWith("\\") ? outPath.getAbsolutePath(): outPath.getAbsolutePath()+"\\") +inPath.getAbsolutePath().substring(12);
                fo=new FileOutputStream(path);

                //一边读一边写
                byte[] bytes=new byte[1024*1024];
                int readCount=0;
                while ( (readCount=fi.read()) !=-1){
                    fo.write(bytes,0,readCount);
                }
                //刷新
                fo.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fi != null) {
                    try {
                        fi.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fo != null) {
                    try {
                        fo.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            //inPath如果是一个文件的话,递归结束
            return;
        }
        //获取源下面的子目录
        File[] files=inPath.listFiles();
        for (File file:files
             ) {
            //是目录的时候创建目录
            if (file.isDirectory()) {
                String srcDir=file.getAbsolutePath();
                /*System.out.println(srcDir.substring(12));*/
                String desDir= (outPath.getAbsolutePath().endsWith("\\") ? outPath.getAbsolutePath(): outPath.getAbsolutePath()+"\\") +srcDir.substring(12);
                /*System.out.println(desDir);*/

                File newFile=new File(desDir);
                if (!newFile.exists()) {
                    newFile.mkdirs();
                }
            }
            //递归调用
            copy(file,outPath);
        }
    }
}


5. IO流+Properties集合的联合使用

IO流:文件的读和写。
Properties:是一个Map集合,key和value都是String类型。

userinfo
package com.bjpowernode.java.io;

import java.io.FileReader;
import java.util.Properties;
/*
IO+Properties的联合应用
非常好的设计理念:
    以后要是经常改变的数据,可以单独写到一个文件中,使用程序动态读取。
    将来只要修改这个文件的内容,java代码不需要改动,不需要重新编译。
    服务器也不需要重启,就可以拿到动态的信息。
*/
public class IoPropertiesTest {
    public static void main(String[] args) throws Exception{
        /*
        Properties是一个Map集合,key和value都是String类型。
        想将userinfo文件中的数据加载到Properties对象当中。
        */

        //新建输入流对象
        FileReader reader=new FileReader("userinfo");
        //新建一个Map集合
        Properties pro=new Properties();
        //调用Properties对象的load方法将文件的数据加载到Map集合中。
        pro.load(reader);//文件中的数据顺着管道加载到Map集合中

        //通过key来获取value呢?
        String username = pro.getProperty("username");
        System.out.println(username);

        String password = pro.getProperty("password");
        System.out.println(password);
    }
}
IO流+properties程序运行结果



笔记来源:B站动力节点Java零基础教程视频

视频链接:https://www.bilibili.com/video/BV1Rx411876f

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容