学习笔记:Java_I/O(part_two)

I/O流

(概述、文件字节流、文件字符流、转换流、缓冲流)

  IO流这部分,算上学习File文件类的时间,总共花了三天时间学习,知识庞杂,种类繁多。但是说到底,各种各样的IO流,核心的方法无外乎构造()、read()、write()三种,根据文件类型的不同,选取不同的IO流。
  东西太多,一次整理不完,因此分成几篇文章来整理,这里是IO概述、文件字节流、文件字符流、转换流四部分


I/O流概述

输入输出的概念

  • 输入输出指的是系统内存与外部设备,网络等进行交互的过程。
    |

I/O概念

  流是一个抽象的概念。当Java程序需要从数据源读取数据时,会开启一个到数据源的流,这个流就是输出流,数据源可以是文件,内存或者网络等。同样,当程序需要输出数据到目的地时也一样会开启一个流,这个流就是输入流,数据目的地也可以是文件、内存或者网络等。流的创建是为了更方便地处理数据的输入输出。
  流对象的操作依赖于操作系统,流通道本身并没有作用

流分类

  • 四大父类(抽象基类)
类名类名操作属性操作对象
字节输入流InputStream读入字节
字符输入流Reader读入字符
字节输出流OutputStream写出字节
字符输出流Writer写出字符

* 根据是否具有额外功能:

类名类名操作属性操作对象额外功能
转换流InputStreamReader
OutputStreamWriter
输入转换流
输出转换流
字节和字符转换字节到字符
缓冲流BufferedXXXXXX的功能XXX的操作对象可以通过缓冲原理实现加速并且实现一些新功能

流对象操作步骤

  1. 创建流子类对象,绑定数据目的(数据源和目标文件)
  2. 调用流方法进行读写操作
  3. .close();释放流对象(Java在程序结束时会自动关闭所有打开的流,但即便如此,显式的关闭任何打开的流仍是一个良好的习惯)。

I/O流注意事项

  • I/O流只能对整个文件进行操作,对文件中个别数据进行操作只能用数据库才能实现。
  • 流对象进行操作的时候经常会抛出IOException异常,所以需要用try{}catch{}语句来写

文件字节流和文件字符流

主要区别

  • 文件字节流可以读写任意文件(不包括文件夹),每次只操作文件中的一个字节。利用字节流创建的新文件可以保证不出错。
  • 文件字符流只能读写文本文件(用.txt格式打开之后能读懂的文件就是文本文件),用字符流创建除文本文件以外任意文件都会造成文件损坏。
  • 字节流不能直接操纵unicode字符,这时字符流的必要性就体现出来,因为一次操纵一个字符(即两个字节),这样就避免了数据传输中,汉字出现乱码等问题。

文件字节流

类名类名操作属性操作对象
文件字节输入流FileInputStream从文件中读入字节
文件字节输出流FileOutputStream写出到文件中字节

文件字节输入流

构造器
  • 作用是绑定输入数据源
  • 文件字节输入流有两种构造方法:
    ——————————
    |FileInputStream(String filePath);|
    |FileInputStream(File file);   |
    ——————————

  • 示例代码

/*
* 这里是在方法内对异常进行处理的完整步骤,比较麻烦,不如throws之后在外边处理好用
* 这里只举例输入流的例子,输出流大同小异,定义时候的区别在其他代码里体现。
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyInputStream {

    public static void main(String[] args) {

        File file = new File("d:\\java\\全职高手.txt");
        FileInputStream in = null;//try外定义方便显式关闭输入流;
        try {
            in = new FileInputStream(file);
        } catch (IOException ea) {
            ea.getMessage();//打印错误信息;
            throw new RuntimeException("\n运行发生错误,请尝试重新运行:");//关闭程序;
        } finally {
            try {
                if (in != null)//判断输入流是否存在且创建成功;
                    in.close();
            } catch (IOException eb) {
                eb.getMessage();
                throw new RuntimeException("\n输入流关闭失败,请尝试重新运行程序");
            }
        }
    }
}
常用方法
方法表达式返回值注意事项
read();int(字节值)每次只读取一个字节,方法返回字节值,到达文件末尾返回-1
read(byte b[])int(实际读取的字节个数)每次读取最多b空间大小的数量的字节,到达末尾返回-1
b的大小太大会浪费空间,太小又影响速度,所以一般定义大小为1024
read(byte b[], int off, int len)int(实际读取的字节个数)off指定数据存放在数组中的位置len指定方法读取的最大字节数
close();void显式关闭输入流

文件字节输出流

构造器
  • 作用是绑定输出的输出目的
  • 文件字节输出流有四种构造方法:
    ———————————————-
    |FileOutputStream(String filePath);        |
    |FileOutputStream(File file);           |   
    |FileOutputStream(String filePath, boolean append); |
    |FileOutputStream(File file, boolean append);   |
    ———————————————-

  • 输出流对象的构造方法可以创建对象,但是如果源文件存在,默认会覆盖原来的文件

  • 所有在构造方法的参数后边常常可以添加另外一个参数boolean append来决定如果文件存在是否覆盖,当apped**值为true**时,输出流会创建新文件覆盖目标文件,否则不覆盖,在目标文件中进行续写

常用方法
方法表达式返回值注意事项
write(int b);void参数虽然是int类型,但是实际传参必须是byte类型
write(byte b[])void写入b空间大小的数量的字节
b的大小太大会浪费空间,太小又影响速度,所以一般定义大小为1024
write(byte b[], int off, int len)voidoff指定数据存放在数组中的位置,即偏移量len指定方法写入的最大字节数
close();void显式关闭输出流

文件字符流

类名类名操作属性操作对象
文件字节输入流FileReader从文件中读入字节
文件字节输出流FileWriter写出到文件中字节

* 转换流失文件字符流的父类,继承关系:
* java.io.FileReader extends java.io.inputStreamReader;
* java.io.inputStreamReader extends java.io.Reader;
* java.io.Reader extends java.lang.Object;
* 文件字符输入流和文件字符输出流都采用系统默认的编码表,中文版Windows系统默认系统编码表为GBK;

文件字符输入流

构造器
  • 作用是绑定输入数据源
  • 文件字符输入流有两种构造方法:
    ————————–
    |FileReader(String filePath);|
    |FileReader(File file);   |
    ————————–
常用方法
方法表达式返回值注意事项
read();int(字符值)每次只读取一个字节,方法返回字节值,到达文件末尾返回-1
read(byte b[])int(实际读取的字符个数)每次读取最多b空间大小的数量的字节,到达末尾返回-1
b的大小太大会浪费空间,太小又影响速度,所以一般定义大小为1024
read(byte b[], int off, int len)int(实际读取的字符个数)off指定数据存放在数组中的位置len指定方法读取的最大字节数
close();void显式关闭输入流

文件字节输出流

构造器
  • 作用是绑定输出的输出目的
  • 文件字符输出流有四种构造方法:
    —————————————-
    |FileWriter(String filePath);        |
    |FileWriter(File file);            |   
    |FileWriter(String filePath, boolean append); |
    |FileWriter(File file, boolean append);   |
    ————————————–
  • 输出流对象的构造方法可以创建对象,但是如果源文件存在,默认会覆盖原来的文件
  • 所有在构造方法的参数后边常常可以添加另外一个参数boolean append来决定如果文件存在是否覆盖,当apped**值为true**时,输出流会创建新文件覆盖目标文件,否则不覆盖,在目标文件中进行续写
  • 与文件字节输出流不同,文件字符输出流只能创建有效的文本文件。
常用方法
方法表达式返回值注意事项
write(int c);void参数虽然是int,但是实际传参要传char类型
write(char b[])void
write(byte b[], int off, int len)voidoff指定数据存放在数组中的位置,即偏移量len指定方法写入的最大字符数
write(String str)字符串中所有字符写到文件中
write(String str, int off, int len)void
flush()void冲流,将数据写入文件(不进行冲流则数据无法写入文件
每次写入数据后进行一次冲流是一个好习惯
close();void显式关闭输出流,再关闭流的同时进行一次冲流操作

文件字节流复制文件代码举例

import java.io.*;

class ClsByte {

    private String originalpath, finalpath;
    private long starttime, endtime;

    public ClsByte(String a, String b) {
        this.originalpath = a;
        this.finalpath = b;
    }

    public void function() {
        System.out.println("字节流复制文件,开始执行:");
        starttime = System.currentTimeMillis();
        File orifile = new File(originalpath);
        File tarfile = new File(finalpath);

        FileOutputStream out = null;
        FileInputStream in = null;
        byte[] data = new byte[1024];

        try {
            in = new FileInputStream(orifile);
            out = new FileOutputStream(tarfile, false);
            int len = 0;
            while ((len = in.read(data)) != -1) {
                out.write(data, 0, len);
            }
        } catch (IOException e) {
            e.getStackTrace();
            throw new RuntimeException("\n文件传输中发生错误,请重试");
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输入流关闭失败,请重试");
            }
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输出流关闭失败,请重试");
            }
        }
        endtime = System.currentTimeMillis();
        System.out.println("文件复制成功\n源文件" + orifile.getAbsolutePath() + "源文件大小" + orifile.getTotalSpace() + "B");
        System.out.println("目标文件" + tarfile.getAbsolutePath() + "目标文件大小" + tarfile.getTotalSpace() + "B");
        System.out.println("消耗时间" + (endtime - starttime) + "millseconds");
    }

}

文件字符流复制文件代码举例

import java.io.*;

import java.util.*;

class ClsChar {

    private String originalpath, finalpath;
    private long starttime, endtime;

    public ClsChar(String a, String b) {
        this.originalpath = a;
        this.finalpath = b;
    }

    public void function() {
        System.out.println("\n字符流复制文件,开始执行:");
        starttime = System.currentTimeMillis();
        File orifile = new File(originalpath);
        File tarfile = new File(finalpath);

        FileReader in = null;
        FileWriter out = null;
        char [] data = new char [1024];

        try {
            in = new FileReader(orifile);
            out = new FileWriter(tarfile, false);
            int len = 0;
            while ((len = in.read(data)) != -1) {
                out.write(new String(data, 0, len));
                out.flush();
            }
        } catch (IOException e) {
            e.getStackTrace();
            throw new RuntimeException("\n文件传输中发生错误,请重试");
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输入流关闭失败,请重试");
            }
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输出流关闭失败,请重试");
            }
        }
        endtime = System.currentTimeMillis();
        System.out.println("文件复制成功\n源文件" + orifile.getAbsolutePath() + "源文件大小" + orifile.getTotalSpace() + "B");
        System.out.println("目标文件" + tarfile.getAbsolutePath() + "目标文件大小" + tarfile.getTotalSpace() + "B");
        System.out.println("消耗时间" + (endtime - starttime) + "millseconds");
    }
}

转换流

转换流特性

  两种转换流都是字符流,区别在于,Output是由字符转字节,Input是由字节转字符

转换流和文件字符流的区别

  • 文件字符流是转换流的子类
  • 文件字符流的编码表已指定为系统默认编码表,转换流则可以指定编码表
  • FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。

  • *
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
  • 这三句代码的功能是一样的,其中第三句最为便捷。
  • 注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。什么时候用子类呢?
    • 条件:
      1. 操作的是文件。
      2. 使用默认编码。

构造器

  • InputStreamReader(InputStream in)
    • 创建的转换流使用默认字符集
  • InputStreamReader(InputStream in, Charset cs)
    • 创建的转换流使用指定的字符集”cs”
  • OutputStreamWriter(OutputStream out)
    • 创建的转换流使用默认字符集
  • OutputStreamWriter(OutputStream out, Charset cs)
    • 创建的转换流使用指定的字符集”cs”

缓冲流

  • Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度。缓冲流必须指向一个底层流,底层流负责将数据读入缓冲区,缓冲流再从缓冲区中读取数据
  • 根据流的分类分类字节缓冲流字符缓冲流
    • 字节缓冲流(BufferedReader/BufferedWriter)的底层流是字节流(InputStream/OutputStream);
    • 字符缓冲流(BufferedInputStream/BufferedOutputStrean)的底层流是字符流(Reader/Writer)

构造器

  • 四种缓冲流的构造器各有两种,这里拿字符缓冲输入流举例:
方法参数含义
BufferedReader(Reader in);创建一个缓冲字符输入流和保存输入流 in,供以后使用。
BufferedInputStream(InputStream in, int size) ;创建一个具有指定的缓冲区大小的字节缓冲输入流,并保存输入流 in,供以后使用。

方法

字节缓冲流

  BufferedInputStream/BufferedOutputStream的方法基本都继承自InputStream/OutputStream,没有什么自己独特的方法,这里不再赘述

字符缓冲流

  同样,这里对于从父类中继承的方法(read(), write(), close(), flush())等都不再赘述,只介绍一些独特的方法。
* 字符缓冲输出流

方法功能注意事项
void newLine();写行分隔符,也就是换行这里体现的是系统无关性
但其实在Windows系统下,在字符串尾部或头部写入“\r\n”是一样的效果
  • 字符缓冲输入流
方法功能注意事项
String readLine();读一行文本读取成功则返回当前行文本,否则返回null

缓冲字符流复制文件代码举例

import java.io.*;

public class ClsBufferedByte {

    private String originalpath, finalpath;
    private long starttime, endtime;

    public ClsBufferedByte(String a, String b) {
        this.originalpath = a;
        this.finalpath = b;
    }

    public void function() {
        System.out.println("\n缓冲字节流复制文件,开始执行:");
        starttime = System.currentTimeMillis();
        File orifile = new File(originalpath);
        File tarfile = new File(finalpath);

        BufferedInputStream in = null;
        BufferedOutputStream out = null;
        FileInputStream rootin = null;
        FileOutputStream rootout = null;
        byte[] data = new byte[1024];

        try {
            rootin = new FileInputStream(orifile);
            rootout = new FileOutputStream(tarfile);
            in = new BufferedInputStream(rootin);
            out = new BufferedOutputStream(rootout);
            int len = 0;
            while ((len = in.read(data)) != -1) {
                out.write(data, 0, len);
            }
        } catch (IOException e) {
            e.getStackTrace();
            throw new RuntimeException("\n文件传输中发生错误,请重试");
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输入流关闭失败,请重试");
            }
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输出流关闭失败,请重试");
            }
        }
        endtime = System.currentTimeMillis();
        System.out.println("文件复制成功\n源文件" + orifile.getAbsolutePath() + "源文件大小" + orifile.getTotalSpace() + "B");
        System.out.println("目标文件" + tarfile.getAbsolutePath() + "目标文件大小" + tarfile.getTotalSpace() + "B");
        System.out.println("消耗时间" + (endtime - starttime) + "millseconds");
    }
}

缓冲字符流复制文件代码举例

import java.io.*;

public class ClsBufferedChar {

    private String originalpath, finalpath;
    private long starttime, endtime;

    public ClsBufferedChar(String a, String b) {
        this.originalpath = a;
        this.finalpath = b;
    }

    public void function() {
        System.out.println("\n缓冲字符流复制文件(按行读取),开始执行:");
        starttime = System.currentTimeMillis();
        File orifile = new File(originalpath);
        File tarfile = new File(finalpath);

        BufferedReader in = null;
        BufferedWriter out  = null;
        FileReader rootin = null;
        FileWriter rootout = null;
        String data = null;
        try {

            rootin = new FileReader(orifile);
            rootout = new FileWriter(tarfile);
            in = new BufferedReader(rootin);
            out  = new BufferedWriter(rootout);

            while ((data = in.readLine()) != null) {
                out.write(data);
                out.flush();
            }

        } catch (IOException e) {
            e.getStackTrace();
            throw new RuntimeException("\n文件传输中发生错误,请重试");
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输入流关闭失败,请重试");
            }
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                throw new RuntimeException("\n输出流关闭失败,请重试");
            }
        }
        endtime = System.currentTimeMillis();
        System.out.println("文件复制成功\n源文件" + orifile.getAbsolutePath() + "源文件大小" + orifile.getTotalSpace() + "B");
        System.out.println("目标文件" + tarfile.getAbsolutePath() + "目标文件大小" + tarfile.getTotalSpace() + "B");
        System.out.println("消耗时间" + (endtime - starttime) + "millseconds");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值