22-04-23 西安 文件流、缓冲流、转换流、对象流、标准流、关闭IO资源的封装类IOUtils(纳命来)

22-04-23 西安 文件流、缓冲流、转换流、对象流、标准流、关闭IO资源的封装类IOUtils(纳命来),第1张

IO流认识一下:

根据数据流向进行分类:

        输入流(其他设备->内存)
        输出流:(内存->其他设备)

根据数据流向单位进行分类:
        字节流:输入输出以字节为单位
        字符流:输入输出以字符为单位

上面俩俩组合后就是IO流的4大基类,这4个都是抽象类

字节输入流 InputStream
字节输出流 OutputStream
字符输入流  Reader
字符输出流  Writer


文件字节输出流 FileOutputStream类 java.io

解:针对文件以字节为单位进行输出 *** 作的工具类。

FileOutputStream类构造器  
    FileOutputStream(File file) 
    FileOutputStream(File file, boolean append) 
    FileOutputStream(String name) //指定一个相对路径,往哪个里输出。
    FileOutputStream(String name, boolean append) //append为true则开启文件续写

FileOutputStream类方法
void write(int b)  //以单字节输出fos.Write(97);
void write(byte[] b)  //以单个字节数组为单位输出  fos.Write("尚硅谷".getBytes())
void write(byte[] b, int off, int len)  //以指定范围的字节数组为单位进行输出,off是起始索引,len是长度
void close()  //fos.close()关闭流资源

代码小Demo:

public class ExceptionDemo {
    public static void main(String[] args) throws ParseException, IOException {
        FileOutputStream fos = new FileOutputStream("a.txt");
        //以单个字节方式写出到文件a.txt
        fos.write(73);
        //以字节数组方式写出到文件a.txt
        byte[] bytes={' ','l','o','v','e',' '};
        fos.write(bytes);
        //以字节数组方式写出到文件a.txt
        byte[] bytes2 = "龙".getBytes(StandardCharsets.UTF_8);
        fos.write(bytes2,0,bytes2.length);
        fos.close();
    }
}


windows下回车换行命令"\r\n"

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("a.txt");
        fos.write("小".getBytes(StandardCharsets.UTF_8));
        fos.write("\r\n".getBytes());//回车换行命令,回车换行是俩个命令
        fos.write("羽".getBytes(StandardCharsets.UTF_8));
        fos.write("\r\n".getBytes());//回车换行命令
        fos.write("毛".getBytes(StandardCharsets.UTF_8));
        fos.close();
    }
}

效果:


输出流的续写功能
输出流在没有打开续写开关时,都会创建一个新的文件覆盖以前的文件。在构造器中打开文件续写开关,默认续写功能关闭
FileOutputStream(String name, boolean append) //append为true则开启文件续写


文件字节输入流  FileInputStream java.io
解:针对文件以字节为单位进行输入(读取) *** 作的工具类。

FileInputStream构造器:
FileInputStream(File file) 
FileInputStream(String name) 

FileInputStream方法
public void close()
public int read()//返回读到的数据字节;如果已到达文件末尾,则返回 -1
public int read(byte[] b)//返回读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回 -1。 

循序渐进大法

1.假设a.txt文件里只有abc三个字母,以单个字节读入

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        //创建文件字节输入流对象
        FileInputStream fis = new FileInputStream("a.txt");
         //假设a.txt文件里只有abc三个字母,以单个字节读入
        System.out.println(fis.read());//读到a-97
        System.out.println(fis.read());//读到b-98
        System.out.println(fis.read());//读到c-99
        System.out.println(fis.read());//读不到,返回-1
    }
}

2.坑爹代码,这里每次循环读了2次,故会读的很是不如意。。。

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        //创建文件字节输入流对象
        FileInputStream fis = new FileInputStream("a.txt");
        //假设a.txt文件里只有abc三个字母,以单个字节读入
        //坑爹代码,这里每次循环读了俩次,故会报错
        while(fis.read()!=-1){
            System.out.println(fis.read());
        }
    }
}

 3.FileInputStream单个字节地正确的读文件,应该这个样子写

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("a.txt");
        //假设a.txt文件里只有abc三个字母,以单个字节读入
        int len;
        while((len=fis.read())!=-1){
            //这里len是读取到的单个字节
            System.out.println(len);
        }
        //关闭资源
        fis.close();
    }
}


4.以字节数组的方式正确的读取文件

这里byte数组长度我们一般给的值是8192,fis.read()之后,byte数组的内容都在变化。把读的数据放到这个byte数组。

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        print();
    }
    public static void print() throws IOException {
//      创建文件字节输入流对象
        FileInputStream fis=new FileInputStream("a.txt");
//      来个小推车 abc
        byte[] bytes=new byte[2];
        int len;
        while((len=fis.read(bytes))!=-1){
            System.out.println("len="+len);//len是读取到的数据个数分别打印2,1
            System.out.println("读取到的内容="+new String(bytes,0,len));
            System.out.println("变换的byte数组:"+ Arrays.toString(bytes));
            System.out.println("============");
        }
    }
}


文件【图片】的复制:一边读一边写

//以字节数组方式复制图片
public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        print();
    }
    public static void print() throws IOException {
        FileInputStream fis = new FileInputStream("girl.jpg");
        FileOutputStream fos = new FileOutputStream("girl_copy.jpg");
/*        byte数组大小
        1、文件的平均单位根据文件进行制定
        2、没有指定,约定俗称8192,8KB*/
        byte[] bytes = new byte[8192];
        int len;
        while((len=fis.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }
//      关闭资源的原则,先开后关,后开先关
        fos.close();
        fis.close();
    }
}

字符流的学习目的

使用字节流读取含有中文的文本文件时,会先将中文字符拆分为字节,进行读写 *** 作,再将拆分后的字节进行重新组合。

字符流读写的时候,不会将字符拆分,直接以字符为单位(不管是中文还是英文,都是一个字符)

  • 文件字节流:用于读写音频、视频、图片,pdf属于图片类。
  • 文件字符流:用于读写文本文件。

文件字符输入流 FileReader  java.io 
解:针对文件以字符为单位进行输入 *** 作的工具类

构造器

FileReader(File file) 
FileReader(String fileName) 

方法:
public void close()
public int read()//读取单个字符
public int read(char[] cbuf)//

1、字符流以单个字符读取

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr=new FileReader("a.txt");
//      以单个字符读取
        int len;
        while((len=fr.read())!=-1){
            char c=(char) len;
            System.out.println(c);
        }
        fr.close();
    }
}

2、字符流以单个字符数组读取

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("a.txt");
//      以单个字符数组读取
        char[] chars = new char[8192];
        int len;
        while ((len = fr.read(chars)) != -1) {
            System.out.println(len);//6
            System.out.println(new String(chars, 0, len));//XYM小羽毛
        }
        fr.close();
    }
}

 


FileWriter 文件字符输出流 java.io
解:针对文件以字符为单位进行输出 *** 作的工具类

构造器:
FileWriter(File file) 
FileWriter(File file, boolean append) 
FileWriter(String fileName)
FileWriter(String fileName, boolean append) 

方法:
public void close();//关闭此流之前调用flush()
public void flush();

public void write(int c);//写单个字符
public void write(char cbuf);//写单个字符数组
public void write(char cbuf,int off,int len);//写单个字符数组,指定范围
public void write(String str);
public void write(String str,int off,int len);//

flush :刷新缓冲区,流对象可以继续使用。
close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了

1、以单个字符,字符数组,字符串输出到文件

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        FileWriter fw=new FileWriter ("a.txt");
//      以单个字符输出
        fw.write(97);
        fw.write(27801);//写汉字沙
//      以字符数组
        fw.write("abc".toCharArray());
//      指定范围字符数组
        fw.write("defgk".toCharArray(),0,3);

        fw.write("\r\n");//回车换行
//      以字符串方式
        fw.write("abc");
//      以指定范围字符串方式
        fw.write("defgk",0,3);
        //fw.flush();把内存缓冲区的东西写到文本文件中
//      做了两步 *** 作,(1)刷新(2)关闭
        fw.close();
    }
}


缓冲流:

开了缓冲外挂,可以做高效的读写 *** 作。
缓冲流之所以高效是因为底层封装了一个长度为8192的字节数组

缓冲字节输入节流 BufferedInputStream java.io
解:针对另外一个字节输入流添加高效输入 *** 作的工具类

构造器:
public BufferedInputStream(InputStream in)
方法:
public void close();
public int read()//
public int read(byte[] b)//

1


缓冲字节输出节流 BufferedOutputStream java.io
解:针对另外一个字节输除流添加高效输出 *** 作的工具类

构造器:
public BufferedOutputStream(OutputStream out)
方法:
public void close();
public void write(int b);//
public void write(byte[] b,int off,int len);//

测试完成211MB的文件复制 *** 作,文件字节流和缓冲字节流效率

结论:在实际开发中往往不会选择缓冲字节流,往往选择长度为8192的字节数组的文件字节流 *** 作,这样会节约很大的空间。

//以单个字节为单位,使用文件字节流读写 *** 作约为80分钟
//以单个字节为单位,使用缓冲字节流读写 *** 作约为12.85秒

//以单个字节数组【1024】为单位,使用文件字节流读写 *** 作约为6.43秒
//以单个字节数组【1024】为单位,使用缓冲字节流读写 *** 作约为1.48秒

//以单个字节数组【8192】为单位,使用文件字节流读写 *** 作约为1.65秒
//以单个字节数组【8192】为单位,使用缓冲字节流读写 *** 作约为1.43秒

//以单个字节数组【1024*1024】为单位,使用文件字节流读写 *** 作约为0.89秒
//以单个字节数组【1024*1024】为单位,使用缓冲字节流读写 *** 作约为0.98秒

缓冲字符输入流 BufferedReader java.io

构造器
public BufferedReader(Reader in)
特有方法
public String readLine()//获取一个文本行,开发中较为常用

1、缓冲字符流一行一行读

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
//      创建缓冲字符输入流
        BufferedReader br=new BufferedReader(new FileReader("a.txt"));
        String len;
        while((len=br.readLine())!=null){
            System.out.println(len);//len是读取的一行文字
        }
        br.close();
    }
}

 

缓冲字符输出流 BufferedWriter java.io

构造器
public BufferedWriter(Writer out)
特有方法
String newLine()//写入一个分隔符

使用缓冲字符输出流可以换行打印

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
//      使用匿名对象创建缓冲字符输出流
        BufferedWriter bw= new BufferedWriter(new FileWriter("a.txt"));
//      进行输出 *** 作
        bw.write("尚");
//      "\r\n"是windows的回车换行
//      bw.write("\r\n");
        bw.newLine();//标准的换行
        bw.write("尚");
        bw.close();
    }
}


编码和解码:

  •       编码:看得懂的内容->字节。
  •       解码: 字节->看得懂的内容

当编码和解码的标准不一致,就会出现乱码 

字符集:字符和十进制对应的表格
常见:ASCII,Unicode,GB, ISO-8859【欧洲】

字符编码:字符集在计算机中的存储规则。

ASCII字符集:ASCII-128字符编码 
ASCII-256字符编码 
Unicode字符集:   UTF-8字符编码
   UTF-16字符编码[java底层]
   UTF-32字符编码
GB字符集:  GB2312字符编码
  GBK字符编码
  GB18030字符编码


转换输入流 InputStreamReader  java.io
解:是字节流通向字符流的桥梁,使用指定的 charset 读取字节并将其解码为字符

构造器
InputStreamReader(InputStream in) 
InputStreamReader(InputStream in, String charsetName)//以指定编码格式读


转换输出流 OutputStreamWriter  java.io
解:是字符流通向字节流的桥梁,可使用指定的 charset 将要写入流中的字符编码成字节

构造器

OutputStreamWriter(OutputStream out) 
OutputStreamWriter(OutputStream out, String charsetName)//以指定编码格式写

指定以哪种方式读取,以哪种方式写入
场景一:用户上传utf-8编码文件。【开发环境utf-8】,下载utf-8的文件。
场景二:用户上传gbk编码文件。【开发环境utf-8】,下载utf-8的文件。
场景三:用户上传utf-8编码文件。【开发环境utf-8】,下载gbk的文件。
场景四:用户上传gbk编码文件。【开发环境utf-8】,下载gbk的文件。

1、乱码问题

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        //FileWriter.txt这个文件是GBK编码的
        FileReader fr = new FileReader("FileWriter.txt");
        char[] chars=new char[8192];
        int len;
        while((len=fr.read(chars))!=-1){
            System.out.println(new String(chars,0,len));//此时会输出乱码
        }
    }
}

2、解决乱码问题

public class ExceptionDemo {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("FileWriter.txt"),"GBK");
        char[] chars=new char[8192];
        int len;
        while((len=isr.read(chars))!=-1){
            System.out.println(new String(chars,0,len));//此时会输出乱码
        }
    }
}


序列化与反序列化

注意:

  1. *** 作的对象的类要实现序列化接口java.io.Serializable 
  2. 进行多个对象的序列化 *** 作【用集合】,针对集合对象进行序列化和反序列化 *** 作。
  3. 在序列化和反序列化中, *** 作对象所在的类文件不能做任何更改。
  4. transient 瞬时的 如果在进行序列化中的过程中,哪个属性信息不想被序列化,可以用transient修饰。【如敏感信息】

ObjectOutputStream  对象输出流  java.io

解:针对跨项目使用对象实现序列化 *** 作的工具类

构造器:
public ObjectOutputStream(OutputStream out) 

方法:
writeObject(Object obj)


ObjectInputStream 对象输入流  java.io
解:针对跨项目使用对象实现反序列化(字节-》对象) *** 作的工具类

构造器:
public ObjectInputStream (InputStream in)
方法:
public final Object readObject();//读取对象

序列化与反序列化演示

public class ExceptionDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
         method01();
         method02();
    }
    public static void method01() throws IOException {
        //序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
        Account account = new Account("001",922113212);// Account要实现序列化接口,启动序列化功能。
        oos.writeObject(account);
        oos.close();
    }
    public static void method02() throws IOException, ClassNotFoundException {
        //反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
        Account account = (Account)ois.readObject();
        System.out.println(account);
        ois.close();
    }

 控制台打印:


标准输入流 System.in      BufferedInputStream类型

1、第二种键盘录入

public class ExceptionDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        System.out.println("输入一个字符串");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
        System.out.println(s);
    }
}


标准输出流 System.out  

PrintStream类  打印流    java.io 
解:针对文本文件进行快速打印。

构造器:
PrintStream(String fileName) 
方法:
public void print()

public void println()

设置系统的打印流流向,输出到print.txt     应用场景:日志

System.out 就是 PrintStream 类型的,只不过它的流向是系统规定的,打印在控制台上。不过,既然 是流对象,我们就可以玩一个" 小把戏 " ,改变它的流向。
public class ExceptionDemo {
    public static void main(String[] args) throws IOException{
        PrintStream ps=new PrintStream("print.txt");
//      重置标准输出流  设置系统的打印流流向,输出到print.txt
        System.setOut(ps);
        System.out.println("hello");
        System.out.println("xiaoyumao");
        ps.println("world");//输出到print.txt
        ps.close();
    }
}

控制台一行没输入:

在print.txt中:


close 关闭资源
1、IO流关闭规则:先开后关,后开先关。
2、实际开发用try...catch..finally。别用throws

IOUtils 中应该要封装8个方法

封装关闭字节输入流的方法
封装关闭字节输出流的方法
封装关闭字节输入流,字节输出流的方法
封装关闭字节输出流,关闭字节输入流的方法

封装关闭字符输入流的方法
封装关闭字符输出流的方法
封装关闭字符输入流,字符输出流的方法
封装关闭字符输出流,关闭字符输入流的方法
//close 关闭资源的工具类
public class IOUtils {
    //构造器私有化
    private IOUtils(){

    }
    //封装关闭字节输入流的方法
    public static void close(InputStream is) throws IOException {
        if(is!=null){
            is.close();
        }
    }

    //封装关闭字节输出流的方法
    public static void close(OutputStream os) throws IOException {
        if(os!=null){
            os.close();
        }
    }

    //封装关闭字节输入流,字节输出流的方法
    public static void close(InputStream is,OutputStream os) throws IOException {
        try{
            close(is);
        }finally{
            close(os);
        }
    }

    //封装关闭字节输出流,关闭字节输入流的方法
    public static void close(OutputStream os,InputStream is) throws IOException {
        try{
            close(os);
        }finally{
            close(is);
        }
    }
}

试试看我们的IOUtils,果然帮我们简化了很多的try...catch..finally,一切尽在不言中

public class ExceptionDemo {
    public static void main(String[] args) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
//          缓冲流
            bis = new BufferedInputStream(new FileInputStream("girl.jpg"));
            bos = new BufferedOutputStream(new FileOutputStream("girl_copy.jpg"));
            int len;
            while ((len = bis.read()) != -1) {
                bos.write(len);//写入字节
            }
        } catch (Exception e) {

        } finally {
            try {
//             关闭资源的原则,先开后关,后开先关
                IOUtils.close(bos, bis);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果:复制了一张图片

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/724053.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存