IO流对象

2020-05-25  本文已影响0人  上炼致知

File

IO概述

要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、u盘等)上;

把以上这种输入和输出操作动作称为IO操作;

File类概述和作用

File类时文件和目录路径名的抽象表示形式

Java中把文件或者目录(文件夹)都封装成File对象

要去操作硬盘上的文件或者文件夹,只要找到File这个类即可;

File类的静态成员变量

File类的构造函数

相对路径和绝对路径

绝对路径:绝对路径是一个固定的路径,从盘符开始;具有唯一性

相对路径:相对路径相对于某个位置;表示路径之间的关系;

File类的获取

File类判断功能

File类创建文件功能

File类创建文件夹功能

File类删除功能

File类list获取功能

文件过滤器

通过listFile()方法,可以获取到一个目录下的所有文件和文件夹,如果想对其进行过滤,比如只想要一个目录下的指定扩展名的文件,可以先把一个目录下的所有文件和文件夹获取到,然后遍历当前获取到的所有内容,遍历过程中进行筛选;

递归

递归概述

递归指在当前方法内调用自己的这种现象

递归分为两种,直接递归和间接递归;

直接递归称为方法自身调用自己;间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法;

/**
 * 递归打印子目录中的所有文件
 * @param args
 * @throws IOException
 */
public static void main(String[] args) throws IOException {
    File file = new File("/Users/syjsuccess/Desktop/ceshi");
    getAllFile(file);
}
public static void getAllFile(File file) {
    File[] listFile = file.listFiles(new MyFilenameFilter());
    for (File fi : listFile) {
            if (fi.isFile()) {
                System.out.println(fi.getName());
            } else if (fi.isDirectory()) {
                getAllFile(fi);
            }
    }
}
public class MyFilenameFilter implements FilenameFilter {
    @Override
    public boolean accept(File dir, String name) {
        return !name.endsWith(".DS_Store");
    }
}

递归适用于:方法中运算的主体不变,但是运行的时候,参与运行的方法参数会变化

注意:递归一定要有出口,必须可以让程序停下;递归次数不能过多;构造方法禁止用递归

示例:斐波那契数列

public class Test {
    public static void main(String[] args) throws IllegaInputException {
        int num = 12;
        fibonacciStr(num);
    }
    public static void fibonacciStr(int num) throws IllegaInputException {
        if (num <= 0) {
            throw new IllegaInputException("不能输入小于等于0的整数");
        }
        int[] arr = new int[num];
        for (int i = 0; i < num; i++) {
            arr[i] = Fib(i + 1);
        }
        System.out.println(Arrays.toString(arr));//[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
    }
    public static int Fib(int num) {

        while (num > 2) {
            return Fib(num - 1) + Fib(num - 2);
        }
        return 1;
    }
}
public class IllegaInputException extends Exception {
    public IllegaInputException() {
        super();
    }
    public IllegaInputException(String str) {
        super(str);
    }
}

字节流

输入和输出

Output:把内存中的数据存储到持久化设备上,这个动作称为输出(写),Output操作;(程序到文件)

Input:把持久化设备上的数据存储到内存中,这个动作称为输入(读),Input操作;(文件到程序)

IO操作:上面的这种输入和输出的动作称为IO操作;

IO流

IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式来进行操作;Java用于操作流的类都在IO包中;

流按流向分为:输入流输出流

流按操作类型分为:字节流字符流

字节流 字符流
字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的; 字符流只能操作纯字符数据,比较方便
父类(抽象):InputStreamOutputStream 父类(抽象):ReaderWriter

字节输出流OutputStream

OutputStream是抽象类,是表示输出字节流的所有类的超类,操作的数据都是字节,定义了输出字节流的几本共性功能方法;

字节输出流FileOutputStream类些字节

OutputStream有很多子类,其中子类FileOutputStream可以用来写入数据到文件;

FileOutputStream类,即文件输出流,用于将数据写入File的输出流

FileOutputStream的构造方法的作用:绑定输出的输出目的,即绑定数目的

文件的续写和换行符号

直接new FileOutputStream(file)这样创建对象写入数据,会覆盖原有的文件,可以使用以下两个构造方法,如果第二个参数为true,则会在文件的末尾续写;

IO异常的处理

IO流的异常处理:try catch finall

public static void main(String[] args) throws IOException {
    File file = new File("/Users/syjsuccess/Desktop/ceshi/output.txt");
    //定义FileOutputStream的引用
    FileOutputStream fos = null;
    try {
        //创建FileOutputStream对象
        fos = new FileOutputStream(file);
        //写出数据
        fos.write("abcde".getBytes());
    } catch (IOException e) {
        System.out.println(e.toString() + "------");
    } finally {
        //一定要判断流对象是否为null,只有不为null时,才可以关闭资源
        if (fos != null) {
            try {
                fos.close();
            }catch (IOException e) {
                throw new RuntimeException(e.toString());
            }
        }
    }
}

字节输入流InputStream

如何把持久化设备中的数据读到内存中,可以通过InputStream可以实现。InputStream是抽象类,是表示字节输入流的所有类的超类,定义了字节输入流的基本共性功能方法

FileInputStream类

InputStream有很多子类,其中子类FileInputStream可以用来读取文件内容;FileInputStream从文件系统中的某个文件中获得输入字节;

字节输入流FileInputStream读取字节数组的实现原理

读取数组的原理.JPG

字节流复制文件---读取单个字节

//定义两个流的对象
FileInputStream fis = null;
FileOutputStream fos = null;
try {
    //建立两个流的对象,绑定数据源和数据目的
    fis = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
    fos = new FileOutputStream("/Users/syjsuccess/Desktop/output.txt");
    //字节输入流,读取1个字节,输出流写1个字节
    int len = 0;
    while ((len = fis.read()) != -1) {
        fos.write(len);
    }
} catch (IOException e) {
    System.out.println(e);
    throw new RuntimeException("文件复制失败");
} finally {
    try {
        if (fos != null) {
            fos.close();
        }
    } catch (IOException ex) {
        throw new RuntimeException("释放资源失败");
    } finally {
        try {
            if (fis != null) {
                fis.close();
            } 
        } catch (IOException e) {
            throw new RuntimeException("释放资源失败");
        }
    }
}

上述代码复制文件有个问题:每次都从源文件读取一个,然后再写到指定文件,接着再读取一个字节,然后再写,这要效率极低;因此需要采用以下数组缓冲提高效率;

字节流复制文件---读取字节数组

long s = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try {
    fis = new FileInputStream("/Users/syjsuccess/Documents/syj/mine/硕士阶段/硕士毕业照/_MG_2346.jpg");
    fos = new FileOutputStream("/Users/syjsuccess/Desktop/_MG_2346.jpg");
    //定义字节数组,缓冲
    byte[] bytes = new byte[1024 * 10];
    //读取数组,写入数组
    int len = 0;
    while ((len = fis.read(bytes)) != -1) {
        fos.write(bytes, 0, len);
    }
} catch (IOException e) {
    System.out.println(e);
    throw new RuntimeException("文件复制失败");
} finally {
    try {
        if (fos != null) {
          fos.close();
        }
    } catch (IOException io) {
        throw new RuntimeException("释放资源失败");
    } finally {
        try {
            if (fis != null) {
                fis.close();
            }
        } catch (IOException io) {
            throw new RuntimeException("释放资源失败");
        }
    }
}

编码表

分类 表示
ASCII 一个字节中的7位就可以表示,对应的字节都是正数;0xxxxxxx
GBK 目前最常用的中文码表,2万的中文和符号;用两个字节表示两个字节第一个是负数,第二个可能是正数
GB18030 最新的中文码表,目前还没正式使用;
unicode 国际标准码表;无论是什么文字,都用两个自己存储
utf-8 基于unicode,一个字节就可以存储的数据就不用两个字节;更加标准化,在每个字节头加入了编码信息;
文字--->(数字):编码;  "abc".getBytes()        byte[]
(数字)---文字:解码;       byte[] bytes = {97, 98, 99}   new String(bytes)

字符输出流Writer

字符输出流写文本FileWrite类

//构造方法,写入的数据目的
FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/output.txt");
//写一个字符
fw.write(100);
fw.flush();

//写一个字符数组
char[] c = {'a', 'b', 'c', 'd', 'e'};
fw.write(c);
fw.flush();

//写入字符数组的一部分
fw.write(c, 2, 2);
fw.flush();

//写如字符串
fw.write("hello");
fw.flush();

fw.close();

字符输入流Reader

字符输入流读取文本FileReader类

//构造方法,绑定数据源
FileReader fr = new FileReader("/Users/syjsuccess/Desktop/ceshi/output.txt");
char[] ch = new char[1024];
int len = 0;
while ((len = fr.read(ch)) != -1) {
    System.out.println(new String(ch, 0, len));
}

fr.close();

flush方法和close方法的区别

flush方法 close方法
用来刷新缓冲区的,刷新后可以再次写出,只有字符流才需要刷新 用来关闭流释放资源的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭之前刷新缓冲区,关闭后不能再写出;

字符流复制文本文件

FileReader fr = null;
FileWriter fw = null;
try {
    fr = new FileReader("/Users/syjsuccess/Desktop/ceshi/output.txt");
    fw = new FileWriter("/Users/syjsuccess/Desktop/output.txt");
    char[] cbuf = new char[1024 * 10];
    int len = 0;
    while ((len = fr.read(cbuf)) != -1) {
        fw.write(cbuf, 0, len);
        fw.flush();
    }
} catch (IOException e) {
    System.out.println(e);
    throw new RuntimeException("复制失败");
} finally {
    try {
        if (fw != null) {
            fw.close();
        }
    } catch (IOException io) {
        throw new RuntimeException("释放资源失败");
    } finally {
        try {
            if (fr != null) {
                fr.close();
            }
        } catch (IOException io) {
            throw new RuntimeException("释放资源失败");
        }
    }
}

转换流

转换流.JPG

OutputStreamWriter类写文本文件

OutputStreamWriter是字符流通向字节流的桥梁;可使用指定的字符编码表,将要写入流中的字符编码成字节;它的作用就是:将字符串按照指定的编码表转成字节,再使用字节流将这些字节写出去

当调用OutputStreamWriter流对象的write方法时,会拿着字符到指定的码表中去进行查询,把查到的字符编码值转换成字节数存放到OutputStreamWriter缓冲区中,然后再调用刷新功能、或者关闭流、或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中;

/*
 * 转换流对象OutputStreamWriter写文本
 * 采用UTF-8编码表写入
 */
//创建字节输出流,绑定文件
FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
//创建转换对象,构造方法,保证字节输出流,并指定编码表是utf-8
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
outputStreamWriter.write("你好");
outputStreamWriter.close();

/*
 * 转换流对象 OutputStreamWriter写文本
 * 文本采用GBK的形式写入
 */
//创建字节输出流,绑定文件
FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
//创建转换对象,构造方法,保证字节输出流,使用gbk编码表
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
outputStreamWriter.write("你好");
outputStreamWriter.close();

InputStreamReader类读取文本文件

InputStreamReader是字节流通向字符流的桥梁,它使用指定的字符编码表读取字节并将其解码问字符;

/*
 *  转换流,InputSteamReader读取文本
 *  采用系统默认编码表,读取GBK文件
 */
//创建字节输入流,传递文本文件
FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
//创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
char[] ch = new char[1024];
int len = inputStreamReader.read(ch);
System.out.println(new String(ch, 0, len));//你好
inputStreamReader.close();


/*
 *  转换流,InputSteamReader读取文本
 *  采用UTF-8编码表,读取文件utf
 */
//创建字节输入流,传递文本文件
FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
//创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
char[] ch = new char[1024];
int len = inputStreamReader.read(ch);
System.out.println(new String(ch, 0, len));//你好
inputStreamReader.close();

转换流和它的子类区别

继承关系:

Writer
    |-- OutputStreamWriter
                        |-- FileWriter

Reader
    |-- InputStreamReader
                        |-- FileReader
OutputStreamWriter和InputStreamReader 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");

一旦要指定其他编码时,就不能使用子类,必须使用字符转换流;

字节--->字符 字符--->字节
看不懂的--->看得懂的 看得懂的--->看不懂的

缓冲流

缓冲流概述:可提高IO流得读写速度分为字节缓冲流与字符缓冲流

字节缓冲流

字节缓冲输出流BufferedOutputStream

/**
 * 写数据到文件的方法
 * 1. 创建流
 * 2. 写数据
 * 3. 关闭流
 */
//创建基本的字节输出流
FileOutputStream fileOut = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
//使用高效的流,把基本的流进行封装,实现速度的提升
BufferedOutputStream out = new BufferedOutputStream(fileOut);
//写数据
out.write("hello".getBytes());
out.close();

字节缓冲输入流BufferedInputStream

/**
 * 从文件中读取数据
 * 1. 创建缓冲流对象
 * 2. 读数据
 * 3. 关闭
 */
FileInputStream fileIn = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
// 创建缓冲流对象,把基本的流包装成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
byte[] bytes = new byte[1024];
//读数据
int len = 0;
while ((len = in.read(bytes)) != -1) {
  System.out.println(new String(bytes, 0, len));
}
//关闭
in.close();

字符缓冲流

字符缓冲输出流BufferedWriter

字符缓冲输出流BufferedWriter特有方法newLine

//创建字符输出流,封装文件
FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
BufferedWriter bfw = new BufferedWriter(fw);
bfw.write(100);
bfw.newLine();//换行
bfw.flush();
bfw.write("你好".toCharArray());
bfw.newLine();
bfw.flush();
bfw.write("你好");
bfw.newLine();
bfw.flush();
bfw.close();

字节缓冲输入流BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取;

int lineNumber = 0;
//创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
//循环调用缓冲流的方法readLine(),结束条件readLine方法返回null
String line = null;
while ((line = bfr.readLine()) != null) {
lineNumber++;
System.out.println(lineNumber + " " + line);
}
bfr.close();

字符缓冲流复制文本文件

public static void main(String[] args) throws IOException {
    int lineNumber = 0;
    //创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
    BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
    BufferedWriter bfw = new BufferedWriter(new FileWriter("/Users/syjsuccess/Desktop/ceshi/1/abc.txt"));
    //读取文本行,读一行,写一行
    String line = null;
    while ((line = bfr.readLine()) != null) {
        bfw.write(line);
        bfw.newLine();
        bfw.flush();
    }
    bfw.close();
    bfr.close();
}

总结

InputStream
        |-- FileInputStream
        |-- BufferedInputStream

OutputStream
        |-- FileOutputStream
        |-- BufferedOutputStream
        
        
Reader
        |-- InputStreamReader
                            |-- FileReader
        |-- BufferedReader
        
Writer
        |-- OutputStreamWriter
                            |-- FileWriter
        |-- BufferedWriter
字节输入流InputStream 字符输入流Reader
FileInputStream操作文件的字节输入流 FileReader文件的字符输入流
BufferedInputStream高效的字节输入流 BufferedReader高效的字符输入流
InputStreamReader输入操作的转换流(把字节流封装成字符流)
字节输出流OutputStream 字符输出流Writer
FileOutputStream操作文件的字节输出流 FileWriter操作文件的字符输出流
BufferedOutputStream高效的字节输出流 BufferedWriter高效的字符输出流
OutputStreamWriter输出操作的转换流(把字节流封装成字符流)

OutputStreamWriter类写文本文件

OutputStreamWriter是字符流通向字节流的桥梁;可使用指定的字符编码表,将要写入流中的字符编码成字节;它的作用就是:将字符串按照指定的编码表转成字节,再使用字节流将这些字节写出去

当调用OutputStreamWriter流对象的write方法时,会拿着字符到指定的码表中去进行查询,把查到的字符编码值转换成字节数存放到OutputStreamWriter缓冲区中,然后再调用刷新功能、或者关闭流、或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中;

/*
 * 转换流对象OutputStreamWriter写文本
 * 采用UTF-8编码表写入
 */
//创建字节输出流,绑定文件
FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
//创建转换对象,构造方法,保证字节输出流,并指定编码表是utf-8
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
outputStreamWriter.write("你好");
outputStreamWriter.close();

/*
 * 转换流对象 OutputStreamWriter写文本
 * 文本采用GBK的形式写入
 */
//创建字节输出流,绑定文件
FileOutputStream fileOutputStream = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
//创建转换对象,构造方法,保证字节输出流,使用gbk编码表
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
outputStreamWriter.write("你好");
outputStreamWriter.close();

InputStreamReader类读取文本文件

InputStreamReader是字节流通向字符流的桥梁,它使用指定的字符编码表读取字节并将其解码问字符;

/*
 *  转换流,InputSteamReader读取文本
 *  采用系统默认编码表,读取GBK文件
 */
//创建字节输入流,传递文本文件
FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/gbk.txt");
//创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gbk");
char[] ch = new char[1024];
int len = inputStreamReader.read(ch);
System.out.println(new String(ch, 0, len));//你好
inputStreamReader.close();


/*
 *  转换流,InputSteamReader读取文本
 *  采用UTF-8编码表,读取文件utf
 */
//创建字节输入流,传递文本文件
FileInputStream fileInputStream = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/1/utf.txt");
//创建转换流对象,构造方法中,包装字节输入流,同时写编码表名
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
char[] ch = new char[1024];
int len = inputStreamReader.read(ch);
System.out.println(new String(ch, 0, len));//你好
inputStreamReader.close();

转换流和它的子类区别

继承关系:

Writer
    |-- OutputStreamWriter
                        |-- FileWriter

Reader
    |-- InputStreamReader
                        |-- FileReader
OutputStreamWriter和InputStreamReader 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");

一旦要指定其他编码时,就不能使用子类,必须使用字符转换流;

字节--->字符 字符--->字节
看不懂的--->看得懂的 看得懂的--->看不懂的

缓冲流

缓冲流概述:可提高IO流得读写速度分为字节缓冲流与字符缓冲流

字节缓冲流

字节缓冲输出流BufferedOutputStream

/**
 * 写数据到文件的方法
 * 1. 创建流
 * 2. 写数据
 * 3. 关闭流
 */
//创建基本的字节输出流
FileOutputStream fileOut = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
//使用高效的流,把基本的流进行封装,实现速度的提升
BufferedOutputStream out = new BufferedOutputStream(fileOut);
//写数据
out.write("hello".getBytes());
out.close();

字节缓冲输入流BufferedInputStream

/**
 * 从文件中读取数据
 * 1. 创建缓冲流对象
 * 2. 读数据
 * 3. 关闭
 */
FileInputStream fileIn = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
// 创建缓冲流对象,把基本的流包装成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
byte[] bytes = new byte[1024];
//读数据
int len = 0;
while ((len = in.read(bytes)) != -1) {
  System.out.println(new String(bytes, 0, len));
}
//关闭
in.close();

字符缓冲流

字符缓冲输出流BufferedWriter

字符缓冲输出流BufferedWriter特有方法newLine

//创建字符输出流,封装文件
FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/2/abc.txt");
BufferedWriter bfw = new BufferedWriter(fw);
bfw.write(100);
bfw.newLine();//换行
bfw.flush();
bfw.write("你好".toCharArray());
bfw.newLine();
bfw.flush();
bfw.write("你好");
bfw.newLine();
bfw.flush();
bfw.close();

字节缓冲输入流BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取;

int lineNumber = 0;
//创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
//循环调用缓冲流的方法readLine(),结束条件readLine方法返回null
String line = null;
while ((line = bfr.readLine()) != null) {
lineNumber++;
System.out.println(lineNumber + " " + line);
}
bfr.close();

字符缓冲流复制文本文件

public static void main(String[] args) throws IOException {
    int lineNumber = 0;
    //创建字符缓冲输入流对象,构造方法传递字符输入流,包装数据源文件
    BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/2/abc.txt"));
    BufferedWriter bfw = new BufferedWriter(new FileWriter("/Users/syjsuccess/Desktop/ceshi/1/abc.txt"));
    //读取文本行,读一行,写一行
    String line = null;
    while ((line = bfr.readLine()) != null) {
        bfw.write(line);
        bfw.newLine();
        bfw.flush();
    }
    bfw.close();
    bfr.close();
}

总结

InputStream
        |-- FileInputStream
        |-- BufferedInputStream

OutputStream
        |-- FileOutputStream
        |-- BufferedOutputStream
        
        
Reader
        |-- InputStreamReader
                            |-- FileReader
        |-- BufferedReader
        
Writer
        |-- OutputStreamWriter
                            |-- FileWriter
        |-- BufferedWriter
字节输入流InputStream 字符输入流Reader
FileInputStream操作文件的字节输入流 FileReader文件的字符输入流
BufferedInputStream高效的字节输入流 BufferedReader高效的字符输入流
InputStreamReader输入操作的转换流(把字节流封装成字符流)
字节输出流OutputStream 字符输出流Writer
FileOutputStream操作文件的字节输出流 FileWriter操作文件的字符输出流
BufferedOutputStream高效的字节输出流 BufferedWriter高效的字符输出流
OutputStreamWriter输出操作的转换流(把字节流封装成字符流)

Properties类

Properties介绍

Properties类表示了一个持久的属性集,Properties可保存在流中或从流中加载,属性列表中每个键及其对应值都是一个字符串;

特点:

  1. 是Hashtable的子类,map集合中的方法都可以用;
  2. 该集合没有泛型,键值都是字符串
  3. 它是一个可以持久化的属性集,键值可以存储到集合中,也可以存储到持久化的设备上,键值的来源也可以是持久化设备;
  4. 有和IO流技术相结合的方法(唯一一个能与IO流交互的集合);
Properties pro = new Properties();
pro.setProperty("a", "1");
pro.setProperty("b", "2");
pro.setProperty("c", "3");
System.out.println(pro);//{b=2, a=1, c=3}

String value = pro.getProperty("c");//3
System.out.println(value);
//方法stringPropertyNames,将集合中的键存储到Set集合,类似Map接口的方法keySet
Set<String> set = pro.stringPropertyNames();
for(String key : set) {
  System.out.println(key + "..." + pro.getProperty(key));
}
/**
 * b...2
 * a...1
 * c...3
 */

Properties集合的方法load

传递任意的字节或者字符输入流,流对象读取文件中的键值对,保存到集合;

/**
 *  1. 创建集合
 *  2. 创建流对象
 *  3. 把流所对应文件中的数据读取到集合中
 *  4. 关闭流
 *  5. 显示集合中的数据
 */
Properties pro = new Properties();
FileReader fr = new FileReader("/Users/syjsuccess/Desktop/ceshi/output.txt");
//调用集合的方法load,传递字符输入流
pro.load(fr);
fr.close();
System.out.println(pro);//{abc=123}

Properties集合的方法store

接收所有的字节或者字符的输出流,将集合中的键值对,写回文件中保存;

/**
 * 1. 创建Properties集合
 * 2. 添加元素到集合
 * 3. 创建流
 * 4. 把集合中的数据存储到流所对应的文件中
 * 5. 关闭流
 */
Properties pro = new Properties();
pro.setProperty("name", "zhangsan");
pro.setProperty("age", "27");
pro.setProperty("email", "12233@qq.com");
FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/output.txt");
//键值对,存回文件,使用集合的方法store传递字符输出流
pro.store(fw, "");
fw.close();

对象的序列化和反序列化

ObjectOutputStream流写对象

//创建字节输出流,封装文件
FileOutputStream fos = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
//创建写出对象的序列化流的对象,构造方法传递字节输出流
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person p = new Person("lisi", 25);
//调用序列化流的方法writeObject,写出对象
//implements Serializable
oos.writeObject(p);
oos.close();

ObjectInputStream流读取对象

FileInputStream fis = new FileInputStream("/Users/syjsuccess/Desktop/ceshi/output.txt");
//创建反序列化流,构造方法中,传递字节输入流
ObjectInputStream ois = new ObjectInputStream(fis);
//调用反序列化方法,readObject()
Object obj = ois.readObject();
System.out.println(obj);//Person{name='lisi', age=25}
ois.close();

静态不能序列化

原因:序列化是把对象数据进行持久化存储,而静态的东西不属于对象,属于类

transient关键字

当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰,只要被transient修饰了,序列化时这个属性就不会被序列化了;

被transient修饰的属性不会被序列化,transient关键字只能修饰成员变量

private transient int age;

Serializable接口的含义

当一个对象要能被序列化,这个对象所属的类必须实现Serializable接口,否则会发生异常NotSerializableException异常;

Serializable标记接口,该接口给需要序列化的类提供了一个序列版本号,serialVersionUID,该版本号的目的在于验证序列化的对象喝对应类是否版本匹配;

给需要序列化的类加上标记,该标记中没有任何抽象方法;只有实现了Serializable接口的类的对象才能被序列化

序列化中的序列号冲突问题

当一个类实现Serializable接口后,创建对象并将对象写入文件,之后更改了源码(比如:将成员变量的修饰符private改成public),再次从文件中读取对象时会报InvalidClassException异常,

序列化中自定义的序列号

定义方式:private static final long serialVersionUID = xxxxxxxxxxxxL;

这样每次编译类是生成的serialVersionUID值都是固定的;

//类自定义了序列号,编译器不会计算序列号
private static final long serialVersionUID = 1234444555L;

打印流

打印流和特性

概述:打印流添加输出数据的功能,使它们能够方便地打印各种数据值表示形式;

打印流根据流分类:字节打印流PrintStream字符打印流PrintWriter;

特点:

  1. 此流不负责数据源,只负责数据目的
  2. 为其他输出流,添加功能;
  3. 永远不会抛出IOException,但是可能抛出别的异常;
  4. 两个打印流的方法,完全一致;
  5. 构造方法就是打印流的输出目的端;

打印输出目的是File对象

/**
 * 打印流,向File对象的数据目的写入数据
 * 方法print println 原样输出
 * write方法走码表
 */
File file = new File("/Users/syjsuccess/Desktop/ceshi/1.txt");
PrintWriter pw = new PrintWriter(file);
pw.println(true);
pw.write(100);
pw.close();

输出语句是char数组

print和println只有打印字符数组是打印内容,其余都是打印数组的地址;

int[] arr = {1};
System.out.println(arr);//[I@1f89ab83
char[] ch = {'a', 'b'};
System.out.println(ch);//ab
byte[] b = {};
System.out.println(b);//[B@e73f9ac

打印流输出目的是String和流对象

/**
 * 打印流输出目的是流对象
 * 可以是字节输出流,可以是字符输出流
 * OutputStream Writer
 */
FileWriter fw = new FileWriter("/Users/syjsuccess/Desktop/ceshi/1.txt");
PrintWriter pw = new PrintWriter(fw);
pw.println("打印流");
pw.close();
/**
 * 打印流输出目的是String文件名
 */
PrintWriter pw = new PrintWriter("/Users/syjsuccess/Desktop/ceshi/1.txt");
pw.println(3.5);
pw.close();

打印流开启自动刷新

/**
 * 打印流可以开启自动刷新功能
 * 满足2个条件:
 *  1. 输出的数据目的必须是流对象OutputStream Writer
 *  2. 必须调用println printf format三个方法中的一个
 */
FileOutputStream fos = new FileOutputStream("/Users/syjsuccess/Desktop/ceshi/1.txt");
PrintWriter pw = new PrintWriter(fos, true);
pw.println("i");
pw.println("love");
pw.println("java");
pw.close();

打印流复制文本文件

/**
 * 打印流实现文本复制
 *      读取数据源 BufferedReader + File 读取文本行
 *      写入数据目的 PrintWriter + println自动刷新
 */
BufferedReader bfr = new BufferedReader(new FileReader("/Users/syjsuccess/Desktop/ceshi/1.txt"));
PrintWriter pw = new PrintWriter(new FileWriter("/Users/syjsuccess/Desktop/ceshi/2.txt"));
String line = null;
while ((line = bfr.readLine()) != null) {
  pw.println(line);
}
pw.close();
bfr.close();

commons-IO

commons-io工具类介绍

解压缩commons-io-2.4.zip文件;

commons-io-2.4.jar是需要导入到项目中的jar包,里面存放的是class文件;

commons-io-2.4-sources.jar是工具类中的源码;

docs是帮助文档;

使用工具类commons-io

导入jar包:

(idea)

  1. 创建lib文件夹,将commons-io-2.4.jar复制到lib文件夹;
  2. 右键,add as a Library;
  3. 右键,building xxx;

(eclipse)

  1. 创建lib文件夹,将commons-io-2.4.jar和common-io-2.4.jar复制到lib文件夹;
  2. 右键commons-io-2.4.jar,build path,add to build path;

IO工具类FilenameUtils

IO工具类FileUtils


总结

字节流

字节输入流InputStream 字节输出流OutputStream
FileInputStream---操作文件的字节输入流 FileOutputStream---操作文件的字节输出流
BufferedInputStream---高效的字节输入流 BufferedOutputStream---高效的字节输出流
ObjectInputStream---反序列化流 ObjectOutputStream---序列化流
PrintStream---字节打印流

字符流

字符输入流Reader 字符输出流Writer
**FileReader **---操作文件的字符输入流 **FileWriter **---操作文件的字符输出流
BufferedReader ---高效的字符输入流 **BufferedWriter **---高效的字符输出流
InputStreamReader ---输入操作的转换流(把字节流封装成字符流) **OutputStreamWriter **---输出操作的转换流(把字节流封装成字符流)
**PrintWriter **---字符打印流

方法:

读取数据方法 写数据方法
read()---一次读一个字节/字符的方法 write() ---一次写一个字节/字符到文件中
read(byte[]/char[])---一次读一个数组数据的方法 write(byte[]/char[]) ---一次写一个数组数据到文件中
readLine() ---一次读一行字符串的方法(BufferedReader类特有的方法 write(String) ---一次写一个字符串内容到文件中
readObject() ---从流中读取对象(ObjectInputStream特有方法 writeObject(Object) ---写对象到流中(ObjectOutputStream类特有方法
newLine() ---写一个换行符号(BufferedWriter类特有方法

向文件中写入数据的过程

  1. 创建输出流对象;
  2. 写数据到文件;
  3. 关闭输出流;

从文件中读取数据的过程

  1. 创建输入流对象;
  2. 从文件中读数据;
  3. 关闭输入流;

文件复制过程

  1. 创建输出流(数据源);
  2. 创建输出流(目的地);
  3. 从输入流中读取数据;
  4. 通过输出流,把数据写入目的地;
  5. 关闭流;

File类方法

异常

try...catch...finally 捕获处理异常;

throws 声明异常;

throw 抛出异常对象;

异常的分类

编译期异常:Exception;

​ |--- 运行期异常:RuntimeException;

编译期异常必须处理,不然无法编译通过;

运行期异常,程序运行过程中产生的异常信息;

Properties

Map集合的一种,它是Hashtable集合的子集合,它键和值都是String类型;是唯一能和IO流结合使用的集合;

实现文件内容的自动追加

实现文件内容的自动刷新

commons-IO

上一篇 下一篇

猜你喜欢

热点阅读