欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

学习笔记:Java_I/O(part_two)

程序员文章站 2024-03-05 15:00:18
...

I/O流

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

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


I/O流概述

输入输出的概念

  • 输入输出指的是系统内存与外部设备,网络等进行交互的过程。
    |
    学习笔记:Java_I/O(part_two)

I/O概念

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

流分类

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

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

类名 类名 操作属性 操作对象 额外功能
转换流 InputStreamReader
OutputStreamWriter
输入转换流
输出转换流
字节和字符 转换字节到字符
缓冲流 BufferedXXX XXX的功能 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) void off指定数据存放在数组中的位置,即偏移量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) void off指定数据存放在数组中的位置,即偏移量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是由字节转字符
学习笔记:Java_I/O(part_two)

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

  • 文件字符流是转换流的子类
  • 文件字符流的编码表已指定为系统默认编码表,转换流则可以指定编码表
  • 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");
    }
}