JAVA-IO流

IO流

  • 1. File类
    • 1.1 File类概述和构造方法
    • 1.2 File类创建功能
    • 1.3 File类判断和获取功能
    • 1.4 File类删除功能
    • 1.5递归
  • 2.IO流的概述和分类
  • 3. 字节流
    • 3.1 两个抽象基类
    • 3.2 FileOutputStream文件输出流
    • 3.3 字节流写数据
    • 3.4 字节流写数据加异常处理
    • 3.5 字节流读数据
    • 3.6 字节缓冲流
  • 4. 字符流
    • 4.1 编码表
    • 4.2 字符串中的编码解码问题
    • 4.3 字符流中的编码解码问题
    • 4.4 字符流写数据
    • 4.5 字符流读数据的两种方式
    • 4.6 改进
    • 4.7 字符缓冲流
    • 4.8 字符缓冲流特有功能
    • 4.9 复制文件的异常处理
  • 5. 特殊操作流
    • 5.1 标准输入输出流
    • 5.2 打印流
    • 5.3 对象序列化流
    • 5.4 Properties

1. File类

1.1 File类概述和构造方法

java.io包下,是一个具体的类,继承object,实现两个接口。File是文件和目录路径名的抽象表示,即文件和目录路径名是通过File封装成对象的。
对于File而言,其封装的并不是真正的文件,而仅仅是一个路径名。它可以是存在的,也可以是不存在的,将来要通过具体的操作把这个路径的内容转换成具体的存在。

File类的构造方法:
File(String pathname);//通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
File(String parent, String child);//从父路径名字符串和子路径名字符串创建新的File实例
File(File parent, String child);//从父抽象路径名和子路径名字符串创建新的File实例

1.2 File类创建功能

public boolean createNewFile();//当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
如果文件不存在,就创建文件,并返回true;
如果文件存在,并返回false;
public boolean mkdir();//创建由此抽象路径名命名的目录
如果目录不存在,就创建文件,并返回true;
如果目录存在,并返回false;
public boolean mkdirs();//创建由此抽象路径名命名的目录,包括任何必须但不存在的父目录
如果目录不存在,就创建文件,并返回true;
如果目录存在,并返回false;

public static void main(String[] args) throws IOException {
        //1.  在E:\code\JAVACode目录下创建一个文件java.txt
        //public boolean createNewFile();//当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
        //把路径封装成对象
        File file1 = new File("E:\\code\\JAVACode\\java.txt");
        System.out.println(file1.createNewFile());

        //2. 在E:\code\JAVACode目录下创建一个目录JavaSE
        //public boolean mkdir();//创建由此抽象路径名命名的目录
        File file2 = new File("E:\\code\\JAVACode\\JavaSE");
        System.out.println(file2.mkdir());

        //3. 在E:\code\JAVACode目录下创建一个多级目录JavaWEB\\HTML
        //public boolean mkdirs();//创建由此抽象路径名命名的目录,包括任何必须但不存在的父目录
        File file3 = new File("E:\\code\\JAVACode\\JavaWEB\\\\HTML");
        System.out.println(file3.mkdirs());

    }

1.3 File类判断和获取功能

public boolean isDirectory();//判断的封装的file是否为目录
public boolean isFile();//判断的封装的file是否为文件
public boolean exists();//判断的封装的file是否为存在
public String getAbsolutePath();//返回封装的file的绝对路径
public String getPath();//返回封装的file的路径的字符串表示
public String getName();//返回封装的file的文件或目录的名称
public String[] list();//返回封装的file的目录下的所有的文件和目录的名称组成的字符串数组
public File[] listFiles();//返回封装的file的目录下的所有的文件和目录封装成的File对象的数组

public static void main(String[] args) {
        //把路径封装成对象
        File file1 = new File("E:\\code\\JAVACode\\java.txt");
        //public boolean isDirectory();//判断的封装的file是否为目录
        System.out.println(file1.isDirectory());//false
        //public boolean isFile();//判断的封装的file是否为文件
        System.out.println(file1.isFile());//true
        //public boolean exists();//判断的封装的file是否为存在
        System.out.println(file1.exists());//true

        //public String getAbsolutePath();//返回封装的file的绝对路径
        System.out.println(file1.getAbsoluteFile());//E:\code\JAVACode\java.txt
        //public String getPath();//返回封装的file的路径的字符串表示
        System.out.println(file1.getPath());//E:\code\JAVACode\java.txt
        //public String getName();//返回封装的file的文件或目录的名称
        System.out.println(file1.getName());//java.txt
        System.out.println("-----------");

        //public String[] list();//返回封装的file的目录下的所有的文件和目录的名称组成的字符串数组
        File file2 = new File("E:\\code\\JAVACode");
        String[] strArr = file2.list();
        for (String arr : strArr) {//增强for
            System.out.println(arr);
        }
        System.out.println("---------");

        //public File[] listFiles();//返回封装的file的目录下的所有的文件和目录封装成的File对象的数组
        File[] fileArr = file2.listFiles();
        for (File file : fileArr) {
//            System.out.println(file);//返回目录下所有文件和目录的绝对路径
//            System.out.println(file.getName());//返回目录下所有文件和目录的名称

            if(file.isFile()){//只返回目录下文件的名称
                System.out.println(file.getName());
            }
        }
    }

1.4 File类删除功能

public boolean delete();//删除封装的File表示的文件或目录,但如果目录里含有内容,则删除不成功

public static void main(String[] args) throws IOException {
        //把路径封装成对象
//        File file1 = new File("E:\\code\\JAVACode\\base01\\java.txt");//绝对路径
        //在当前模块下创建java.txt文件
        File file1 = new File("java.txt");//相对路径,E:\code\JAVACode\base01\src
        System.out.println(file1.createNewFile());
        //public boolean delete();//删除封装的File表示的文件或目录
        System.out.println(file1.delete());
        System.out.println("-------------------");

        //在当前模块下创建JavaSE目录
        File f1 = new File("JavaSE");
        System.out.println(f1.mkdir());
        //删除当前模块下的JavaSE目录
        System.out.println(f1.delete());
        System.out.println("-------------------");

        //在当前模块下创建JavaSEE目录,然后在目录下创建java.txt文件
        File f2 = new File("JavaSEE");
        System.out.println(f2.mkdir());
        File f3 = new File("JavaSEE\\java.txt");
        System.out.println(f3.createNewFile());
        //删除当前模块下的JavaSEE目录
        //当删除的目录里是含有内容的,则删除不成功
//        System.out.println(f2.delete());//false
        System.out.println(f3.delete());
        System.out.println(f2.delete());
    }

1.5递归

递归:指方法定义中调用方法本身的现象。

/*遍历目录
需求:给定一个路径,通过递归完成遍历该目录下的所有内容,并把所有文件的绝对路径输出

* */
public class FileDemo05 {
    public static void main(String[] args) {
        File file = new File("E:\\code\\JAVACode\\base01\\src\\oop");
        getN(file);
    }
    public static void getN(File f){
        File[] file = f.listFiles();
        for (File f1 : file) {
            if(f1.isFile()){//是文件就直接输出绝对路径
                System.out.println(f1.getAbsoluteFile());
            }else{//是目录就通过递归,继续遍历得到文件
                getN(f1);
            }
        }
        
    }
}

2.IO流的概述和分类

IO流概述:IO输入/输出(input/output)
流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输。
IO流就是用来处理设备间数据传输问题的。
IO流的分类:

  • 按数据的流向:输入流(读数据)/输出流(写数据);
  • 按数据的类型:字节流(字节输入流、字节输出流)/字符流(字符输入流、字符输出流)。
    如果数据可以通过Windows自带的记事本软件打开,不乱码,可以读懂内容,就可以使用字符流;否则使用字节流。如果不知道使用哪种类型的流,就选择使用字节流。

3. 字节流

3.1 两个抽象基类

class InputStream,在java.io包下,继承Object,实现Closeable接口。这个抽象类是表示输入字节流的所有类的超类。
class OutputStream,在java.io包下,继承Object,实现Closeable、Flushable接口。这个抽象类是表示输出字节流的所有类的超类。
这个抽象基类的子类名称特点:子类名称都是以其父类名称作为后缀。

3.2 FileOutputStream文件输出流

FileOutputStream文件输出流是OutputStream的子类:用于将数据写入File或者FileDescriptor的输出流。

构造方法:
FileOutputStream(String name);//创建文件输出流以指定的名称创建文件
常用方法:
void write(int b);//将指定的字节写入此文件输出流
void close(); // 释放资源,关闭此文件输出流,并释放与此流相关联的任何系统资源

使用字节输出流写数据的步骤:

  1. 创建字节输出流对象(调用系统功能创建了文件;创建字节输出流对象;让字节输出流对象指向了创建好的文件)
  2. 调用字节输出流对象的写数据的方法
  3. 释放资源,关闭此文件输出流,并释放与此流相关联的任何系统资源
public static void main(String[] args)  throws IOException {
        //创建字节输出流对象,以指定的文件名称创建文件
        FileOutputStream fos = new FileOutputStream("E:\\code\\JAVACode\\fos.txt");
        /*上一句代码做的三件事情:
        1.调用系统功能创建了文件
        2.创建了字节输出流对象
        3.让字节输出流对象指向了创建好的文件
        * */
        //void write(int b);//将指定的字节写入此文件输出流
        fos.write(97);
        //void close(); // 释放资源,关闭此文件输出流,并释放与此流相关联的任何系统资源
        fos.close();
    }

3.3 字节流写数据

字节流写数据的三种方法
void write(int b);//一次写一字节
void write(byte[] b);//一次写一个字节数组数据
void write(byte[] b, int off, int len);//一次写一个字节数组的部分数据(从索引off开始,长度为len)

public static void main(String[] args) throws IOException {
        //创建字节输出流对象
        FileOutputStream fos = new FileOutputStream("E:\\code\\JAVACode\\fos.txt");
        //void write(int b);//一次写一字节
        fos.write(98);//写入‘b’
        //void write(byte[] b);//一次写一个字节数组数据
//        byte[] b = {99, 100, 101, 102};
//        fos.write(b);
        //byte[] getBytes();//返回字符串对应的字节数组,String的方法
        byte[] b = "cdef".getBytes();
        fos.write(b);
        fos.write(b, 1, 3);

        // 释放资源
        fos.close();
    }

字节流写数据的遇到的两个小问题:

  1. 字节流写数据如何实现换行
    windows:\r\n
    Linux:\n
    Mac:\r
  2. 字节流写数据如何实现追加写入
    构造方法

public FileOutputStream(String name, boolean oppend); //创建文件输出流,以指定的名称写入文件,如果oppend为true则将字节写入文件的末尾而不是开头,并且如果文件已经存在,就不再重建,而是继续写字节
String自带的getBytes()//返回字符串对应的字节数组 byte[]

public static void main(String[] args) throws IOException {
        //创建字节输出流对象
//        FileOutputStream fos = new FileOutputStream("E:\\code\\JAVACode\\fos.txt");
        //解决问题:字节流写数据如何实现追加写入
        //创建文件输出流,以指定的名称写入文件,如果oppend为true则将字节写入文件的末尾而不是开头
        FileOutputStream fos = new FileOutputStream("E:\\code\\JAVACode\\fos.txt", true);
        //写数据
        for (int i = 0; i < 10; i++) {
            fos.write("hello".getBytes());
            fos.write("\n".getBytes());
        }
        //释放资源
        fos.close();
    }

3.4 字节流写数据加异常处理

try{
//可能出现的异常代码
}catch(异常类名 变量名){
//异常的处理代码
}finally{
//一定会执行的操作,除非JVM退出,一般放关闭的代码
}

public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("E:\\code\\JAVACode\\fos.txt");
            fos.write("hello".getBytes());

        }catch (IOException e){
            e.printStackTrace();
        }finally {//保证资源一定会释放
            if (fos != null) {
                //finally控制的语句一定会执行,除非JVM退出
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

3.5 字节流读数据

FileInputStream文件输入流是InputStream的子类:用于获取File或者FileDescriptor中数据的输入流。

构造方法:
FileInputStream(String name);//创建文件输入流,读取指定名称文件中的数据
常用方法:
void write(int b);//将指定的字节写入此文件输出流
void close(); // 释放资源,关闭此文件输出流,并释放与此流相关联的任何系统资源

使用字节输入流读取数据的步骤:

  1. 创建字节输入流对象
    (调用系统功能创建了文件;创建字节输出流对象;让字节输出流对象指向了创建好的文件)
  2. 调用字节输入流对象读取数据
  3. 释放资源,关闭此文件输入流,并释放与此流相关联的任何系统资源

读取数据用到的方法:

int read();//读取一次一个字节数据,文件读到末尾返回-1
int read(byte[] b);//读取一次一个字节数组,从该输入流最多读取b.length个字节到一个字节数组中,返回的是字节数组的长度
String(byte[] bytes); //将bytes数组转换成String,需要实例化为字符串

public static void main(String[] args) throws IOException {
        //创建字节输入流对象
        FileInputStream fis = new FileInputStream("E:\\code\\JAVACode\\fos.txt");
        /*文件中:
        hello
//        world
//        * */
//        //调用字节输入流对象读取数据
//        //int read(byte[] b);//读取b的长度的数据,为byte数组
//
//        byte[] by = new byte[5];//字节数组的长度为5
//
//        //第一次读取数据
//        int len = fis.read(by);//读取一个字节数组的数据,len与by字节数组的长度相同
//        System.out.println(len);//5
//        //String(byte[] bytes); //将byte数组转换成String
//        System.out.println(new String(by, 0, len));//hello
//        //第二次读取数据
//        len = fis.read(by);//读取的数据的字节个数
//        System.out.println(len);//如果为-1,代表为末尾;Windows中的换行符为“\r\n”为两个字符
//        //String(byte[] bytes); //将byte数组转换成String
//        System.out.println(new String(by, 0, len));//\r\nwor
//        //第三次读取数据
//        len = fis.read(by);//读取的数据的字节个数
//        System.out.println(len);//2,之后到达末尾
//        //String(byte[] bytes); //将byte数组转换成String
//        System.out.println(new String(by, 0, len));//ld\r\n
        /*
        * hello
        * wolrd
        * 第一次:hello   5
        * 第二次:\r\nwor 5
        * 第三次:ld      2
        * */

        //循环读取内容,每次最多读长度为1024个字节数组
        byte[] by = new byte[1024];//长度一般为1024及其整数倍
        int len;
        while((len = fis.read(by)) != -1){
            System.out.print(new String(by, 0, len));
        }

        //释放资源,关闭此文件输出流,并释放与此流相关联的任何系统资源
        fis.close();

    }

3.6 字节缓冲流

BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
BufferedInputStream:将创建一个内部缓冲区数组。当从流中读取字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。

构造方法:
BufferedOutputStream(OutputStream out);
BufferedInputStream(InputStream in);

为什么构造方法需要的是字节流?

字节缓冲流仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作。

 public static void main(String[] args) throws IOException {

        //字节缓冲流:BufferedOutputStream(OutputStream out);
//        FileOutputStream fos = new FileOutputStream("E:\\code\\JAVACode\\bos.txt");
//        BufferedOutputStream bos = new BufferedOutputStream(fos);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\code\\JAVACode\\bos.txt"));
        //写数据
        bos.write("hello\r\n".getBytes());
        bos.write("world\r\n".getBytes());
        //释放资源
        bos.close();


        //字节缓冲流:BufferedInputStream(InputStream in);
//        FileInputStream fis = new FileInputStream("E:\\code\\JAVACode\\bos.txt");
//        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\code\\JAVACode\\bos.txt"));

        //读数据(一次读一个字节)
        int by;
        while((by = bis.read()) != -1){
            System.out.print((char)by);
        }


        //读数据(一次读一个字节数组)
//        int len;
//        byte[] bys = new byte[1024];
//        while((len = bis.read(bys)) != -1){
//            System.out.print(new String(bys, 0, len));
//        }

        //释放资源
        bis.close();

    }

4. 字符流

由于字节流操作中文不是特别方便,所以提供了字符流。字符流 = 字节流 + 编码表。
如何识别中文?汉字在存储时,无论选择哪种编码存储,第一个字都是负数。

4.1 编码表

计算机中存储的信息都是用二进制表示的。编码:按照某种规则,将字符存储到计算机中;解码:将存储在计算机中的二进制数按某种规则解析显示出来。字符集:是一个系统支持的所有的字符集合。
计算机要准确的存储和识别各种字符集符号,就需要进行符号编码,一套字符集必须至少有一套字符编码。常见的字符集有:ASCII字符集、GBXXX、Unicode等。

4.2 字符串中的编码解码问题

编码

byte[] getBytes();//使用平台默认字符集编码,将结果存储到新的字节数组中
byte[] getBytes(String charsetName);//使用指定的字符集编码,将结果存储到新的字节数组中

解码

String的构造方法:
String(byte[] bytes);//使用平台默认字符集解码指定的字节数组,构造新的String
String(byte[] bytes, String charsetName);//使用指定字符集解码指定的字节数组,构造新的String

public class StringDemo01 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //编码
        String s = "中国";
        //byte[] getBytes();//使用平台默认字符集编码,将结果存储到新的字节数组中
        byte[] bys1 = s.getBytes();//[-28, -72, -83, -27, -101, -67]
        // byte[] getBytes(String charsetName);//使用指定的字符集编码,将结果存储到新的字节数组中
        byte[] bys2 = s.getBytes("UTF-8");//[-28, -72, -83, -27, -101, -67]
        byte[] bys3 = s.getBytes("GBK");//[-42, -48, -71, -6]
        System.out.println(Arrays.toString(bys1));
        System.out.println(Arrays.toString(bys2));
        System.out.println(Arrays.toString(bys3));

        //解码
        //String(byte[] bytes);//使用平台默认字符集解码指定的字节数组,构造新的String
//        String ss = new String(bys);
        //String(byte[] bytes, String charsetName);//使用指定字符集解码指定的字节数组,构造新的String
        String ss = new String(bys3, "GBK");
        System.out.println(ss);

    }
}

4.3 字符流中的编码解码问题

字符流抽象基类:
Reader:字符输入流的抽象类
Writer:字符输出流的抽象类
字符流中和编解码问题相关的两个类:

InputStreamReader://是从字节流–>字符流的桥梁,读取字节并解码为字符。
InputStreamReader(InputStream in);//创建一个使用默认字符解码,将读取的的字节解码为成字符
InputStreamReader(InputStream in, String charsetName);//创建一个使用指定字符解码,将读取的的字节解码为成字符

OutputStreamWriter://是从字符流–>字节流的桥梁,使用编写讲写入的字符编码为字节。
OutputStreamWriter(OutputStream out);//创建一个使用默认字符编码,将写入的字符编码成字节
OutputStreamWriter(OutputStream out, String charsetName);//创建一个使用指定字符编码,将写入的字符编码成字节

public static void main(String[] args) throws IOException {
        //OutputStreamWriter(OutputStream out);//创建一个使用默认字符编码,将写入的字符编码成字节
//        FileOutputStream fos = new FileOutputStream("E:\\code\\JAVACode\\osw.txt");
//        OutputStreamWriter osw = new OutputStreamWriter(fos);
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\code\\JAVACode\\osw.txt"));

        //OutputStreamWriter(OutputStream out, String charsetName);//创建一个使用指定字符编码,将写入的字符编码成字节
        //编码:UTF-8
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\code\\JAVACode\\osw.txt"), "UTF-8");
        //编码:GBK
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\code\\JAVACode\\osw.txt"), "GBK");

        //写数据
        osw.write("中国");
        //释放资源
        osw.close();

        //InputStreamReader(InputStream in);//创建一个使用默认字符编码,将读取的的字节解码为成字符

        //InputStreamReader(InputStream in, String charsetName);//创建一个使用指定字符编码,将读取的的字节解码为成字符
        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\code\\JAVACode\\osw.txt"), "GBK");

        //读数据(一次读取一个字符数据)
        int ch;
        while((ch = isr.read()) != -1){
            System.out.print((char)ch);
        }

        //释放资源
        isr.close();
    }

4.4 字符流写数据

5种字符流写数据的方式:

void write(int c);//写一个字符
void write(char[] cbuf);//写一个字符数组
void write(char[] cbuf, int off, int len);//写字符数组的一部分
void write(String str);//写一个字符串
void write(String str, int off, int len);//写字符串的一部分

void flush();//刷新流,还可以继续写数据
void close();//关闭流,释放资源,但需要先刷新再关闭,关闭后不可再写

4.5 字符流读数据的两种方式

2种字符流读数据的方式:

int read();//一次读取一个字符数据
int read(char[] cbuf);//一次读取一个字符数组数据

public static void main(String[] args) throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\code\\JAVACode\\osw.txt"));
        //写
        //void write(int c);//写一个字符
        osw.write(97);//'a'
        //void write(char[] cbuf);//写一个字符数组
        char[] cbuf = {'b', 'c', 'd', 'e'};
        osw.write(cbuf);
        osw.write("\r\n");
        //void write(char[] cbuf, int off, int len);//写字符数组的一部分
        //参数为字符数组,起始位置,长度
        osw.write(cbuf, 3, 1);
        //void write(String str);//写一个字符串
        osw.write("\r\n");
        osw.write("hello");
        //void write(String str, int off, int len);//写字符串的一部分
        osw.write("\r\n");
        osw.write("hello world", 5, 6);
        //void flush();//刷新流
        osw.flush();
        //释放资源:关闭流,但先刷新
        osw.close();

        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\code\\JAVACode\\osw.txt"));
        //读
//        int read();//一次读取一个字符数据
//        int ch;
//        while((ch = isr.read()) != -1){
//            System.out.print((char)ch);
//        }

        //int read(char[] cbuf);//一次读取一个字符数组数据
        char[] chs = new char[1024];
        int len;
        while ((len = isr.read(chs)) != -1){
            System.out.print(new String(chs, 0, len));
        }
        //释放资源
        isr.close();
    }

4.6 改进

由于转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以为了简化书写,转换流提供了对应的子类:

FileReader(String FileName);//用于读取字符文件的便捷类
FileWriter(String FileName);//用于写入字符文件的便捷类

public static void main(String[] args) throws IOException {
//        1. 根据数据源创建字符输入流对象
//        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\code\\JAVACode\\base01\\src\\IO\\file\\FileDemo01.java"));
        FileReader fr = new FileReader("E:\\code\\JAVACode\\base01\\src\\IO\\file\\FileDemo01.java");
//        2. 根据目的地创建字符输出流对象
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\code\\JAVACode\\hello.java"));
        FileWriter fw = new FileWriter("E:\\code\\JAVACode\\hello.java");
//        3. 读写数据,复制文件
        //读(一次一个字符)
//        int ch;
//        while ((ch = fr.read()) != -1){
//            fw.write(ch);
//        }
        //读(一次一个字符数组)
        char[] chs = new char[1024];
        int len;
        while ((len = fr.read(chs)) != -1){
            fw.write(chs, 0, len);
        }
//        4. 释放资源
        fr.close();
        fw.close();

    }

4.7 字符缓冲流

提高读写数据的效率
BufferedReader:继承Reader,从字符输入流读取文本,缓冲字符,以提供字符、数组和行的高效读取。可以指定缓冲区的大小,或者接收默认的大小。默认值足够大,可以满足于大多数用途。

BufferedReader(Reader in);

BufferedWriter:继承Writer,将文本写入字符输出流,缓冲字符,以提供单个字符、数组和字符串的高效写入。

BufferedWriter(Writer on);

public static void main(String[] args) throws IOException {
        //BufferedWriter(Writer on);
//        FileWriter fw = new FileWriter("E:\\code\\JAVACode\\bw.txt");
//        BufferedWriter bw = new BufferedWriter(fw);
        BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\code\\JAVACode\\bw.txt"));
        //写
        bw.write("hello\r\n");
        bw.write("world\r\n");
        //释放资源
        bw.close();

        //BufferedReader(Reader in);
//        FileReader fr = new FileReader("E:\\code\\JAVACode\\bw.txt");
//        BufferedReader br = new BufferedReader(fr);
        BufferedReader br = new BufferedReader(new FileReader("E:\\code\\JAVACode\\bw.txt"));
        //读(一次一个字符)
        int ch;
        while ((ch = br.read()) != -1) {
            System.out.print((char) ch);
        }
        //读(一次一个字符数组)
//        char[] chs = new char[1024];
//        int len;
//        while ((len = br.read(chs)) != -1) {
//            System.out.print(new String(chs, 0, len));
//        }
        //释放资源
        br.close();

    }

4.8 字符缓冲流特有功能

BufferedWriter:
void newLine();//写一行行分隔符,行分隔符字符串由系统属性定义
BufferedReader: //从控制台读数据
public String readLine(); //读一行文字,结果包含行的内容的字符串,不包含任何行终止字符;如果到达流的结尾,则为null。

public static void main(String[] args) throws IOException {
        BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\code\\JAVACode\\bw.txt"));
        //void newLine();//写一行行分隔符,行分隔符字符串由系统属性定义
        //写
        bw.write("hello");
        bw.newLine();
        bw.write("world");
        bw.newLine();
        bw.close();


        BufferedReader br = new BufferedReader(new FileReader("E:\\code\\JAVACode\\bw.txt"));
        //读(一行文字)
        String s;
        while ((s = br.readLine()) != null) {
            System.out.println(s);
        }
        //释放资源
        br.close();
    }

4.9 复制文件的异常处理

  1. 抛出异常;
  2. 采用try…catch…finally的做法;
  3. JDK7改进方案:try(定义流对象){}catch(){}----自动释放资源
  4. JDK9改进方案:定义输入流对象;定义输出流对象;try(输入流对象;输出流对象){ }catch(){ }----自动释放资源

抛出异常

//方法一:抛出异常,在main方法中处理
    private static void copyFileString01() throws IOException {
        FileReader fr = new FileReader("E:\\code\\JAVACode\\Student.txt");
        FileWriter fw = new FileWriter("E:\\code\\JAVACode\\Student.txt");
        char[] ch = new char[1024];
        int len;
        while ((len = fr.read(ch)) != -1) {
            fw.write(ch, 0, len);
        }
        fr.close();
        fw.close();

    }

try…catch…finally

private static void copyFileString02() {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            fr = new FileReader("E:\\code\\JAVACode\\Student.txt");
            fw = new FileWriter("E:\\code\\JAVACode\\Student.txt");
            char[] ch = new char[1024];
            int len;
            while ((len = fr.read(ch)) != -1) {
                fw.write(ch, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }


    }

JDK9改进方案:定义输入流对象;定义输出流对象;try(输入流对象;输出流对象){ }catch(){ }----自动释放资源

private static void copyFileString04() {

        try( FileReader fr = new FileReader("E:\\code\\JAVACode\\Student.txt");
             FileWriter fw = new FileWriter("E:\\code\\JAVACode\\Student.txt");){

            char[] ch = new char[1024];
            int len;
            while ((len = fr.read(ch)) != -1) {
                fw.write(ch, 0, len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        //自动释放资源,所以不需要收到释放资源
//        fr.close();
//        fw.close();
    }

JDK7改进方案:try(定义流对象){}catch(){}----自动释放资源

private static void copyFileString03() throws IOException {
        FileReader fr = new FileReader("E:\\code\\JAVACode\\Student.txt");
        FileWriter fw = new FileWriter("E:\\code\\JAVACode\\Student.txt");
        try(fr; fw){

            char[] ch = new char[1024];
            int len;
            while ((len = fr.read(ch)) != -1) {
                fw.write(ch, 0, len);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        //自动释放资源,所以不需要收到释放资源
//        fr.close();
//        fw.close();

    }

5. 特殊操作流

5.1 标准输入输出流

System类中有两个静态成员变量:
标准输入流:通常该流对应于键盘输入或者由主机环境或用户指定的另一个输入流。

public static final InputStream in;

public static void main(String[] args) throws IOException {
        //InputStream 为字节输入流的抽象基类
        //读取的是键盘输入的内容
        InputStream is = System.in;
        //读(一次一个字节)
//        int by;
//        while ((by = is.read()) != -1) {
//            System.out.print((char) by);
//        }
        //使用字符流读数据
        //如何将字节流转成字符流---使用转换流
        InputStreamReader isr = new InputStreamReader(is);

        //使用字符流读数据实现一次读一行数据
        //但,一次读一行数据是字符缓冲输入流特有的方法
        BufferedReader br = new BufferedReader(isr);
        System.out.println("请输入一个字符串:");
        String s = br.readLine();
        System.out.println("你输入的字符串是:" + s);

        System.out.println("请输入一个整数:");
        int i = Integer.parseInt(br.readLine());
        System.out.println("你输入的整数是:" + i);

    }

标准输出流:通常该流对应于显示输出或由主机环境或用户指定的另外一个输出目标。

public static final PrintStream out;

public static void main(String[] args) {
        //PrintStream 为字节输出流的抽象基类,能够方便打印各种数据值
        PrintStream ps = System.out;

        ps.print("hello");
        ps.print(100);

        ps.println("hello");
        ps.println(100);
        //System.out本质是一个字节输出流,PrintStream类有的方法,System.out都可以使用
        System.out.println("hello");
        System.out.println(100);

        System.out.println();//可以无参
//        System.out.print();//不能无参

    }

5.2 打印流

  1. 字节打印流PrintStream
    PrintStream:在java.io下,继承OutputStream输出流
    特点:只负责输出数据,不负责读取数据;有自己特有的方法。

PrintStream(String fileName);//使用指定的文件名创建新的打印流

使用继承的父类的write()写数据,查看时会转码;使用自己特有的方法写数据(print,println),查看的数据原样输出。

public static void main(String[] args) throws FileNotFoundException {
        //PrintStream(String fileName);//使用指定的文件名创建新的打印流
        PrintStream ps = new PrintStream("E:\\code\\JAVACode\\ps.txt");
        //写
        //继承父类的write()
        ps.write(97);//a
        ps.write(98);//b
        //自己特有的方法
        ps.println();
        ps.print(97);//97
        ps.println();//\n换行
        ps.print(98);//98
        ps.println();

        ps.println(97);
        ps.println(98);

        //释放资源
        ps.close();

    }
  1. 字符打印流PrintWriter
    PrintWriter:在java.io下,继承Writer字符输出流

PrintWriter(String fileName);//使用指定的文件名创建一个新的字符打印流PrintWriter,而不需要自动执行刷新
PrintWriter(Writer out, boolean autoFlush);//创建一个新的字符打印流PrintWriter;out:字符输出流; autoFlush:一个布尔值,如果为真则println,printf,或format方法将刷新输出缓冲区

public static void main(String[] args) throws IOException {
        //PrintWriter(String fileName);//使用指定的文件名创建一个新的字符打印流PrintWriter,而不需要自动执行刷新
//        PrintWriter pw = new PrintWriter("E:\\code\\JAVACode\\pw.txt");
        //PrintWriter(Writer out, boolean autoFlush);//创建一个新的字符打印流PrintWriter
        //out:字符输出流;  autoFlush:一个布尔值,如果为真则println,printf,或format方法将刷新输出缓冲区
        PrintWriter pw1 = new PrintWriter(new FileWriter("E:\\code\\JAVACode\\pw.txt"), true);
        //写
//        pw.write("hello");//需要刷新
//        pw.write("\r\n");
//        pw.write("world");
//        pw.write("\r\n");
//
//        pw.println("java");
//        pw.println("hello");

        pw1.println("hello");//自动刷新
        pw1.println("world");

        //释放资源
//        pw.close();
        pw1.close();
    }
}

5.3 对象序列化流

对象序列化流:就是将对象保存到磁盘中或者在网络中传输对象。这种机制使用一个字节序列表示一个对象,该字节序列包含:对象的类型,对象的数据和对象中存储的属性等信息,字节序列写到文件之后,相当于文件中持久保存了一个对象的信息。反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:
对象序列化流:ObjectOutputStream

构造方法:
ObjectOutputStream(OutputStream out);//创建一个写入指定的OutputStream的ObjectOutputStream
序列化对象的方法:
void writeObject(Object obj);//将指定的对象写入ObjectOutputStream
NotSerializableException:抛出一个实例需要一个Serializable接口,序列化运行时或实例的类可能会抛出此异常。

一个对象要想序列化,该对象所述的类必须实现Serializable接口;Serializable是一个标记接口,实现该接口,不需要重写任何方法。

public static void main(String[] args) throws IOException {
        //ObjectOutputStream(OutputStream out);//创建一个写入指定的OutputStream的ObjectOutputStream
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\code\\JAVACode\\oos.txt"));
        Student s1 = new Student("zrr", 18);
        oos.writeObject(s1);
        oos.close();


    }

对象反序列化:ObjectInputStream

构造方法:
ObjectInputStream(InputStream in);//创建从指定的InputStream读取的ObjectInputStream
反序列化对象的方法:
Object readObject();//从ObjectInputStream读取一个对象
NotSerializableException:抛出一个实例需要一个Serializable接口,序列化运行时或实例的类可能会抛出此异常

一个对象要想序列化,该对象所述的类必须实现Serializable接口; Serializable是一个标记接口,实现该接口,不需要重写任何方法。

public static void main(String[] args) throws IOException, ClassNotFoundException {
        //ObjectInputStream(InputStream in);//创建从指定的InputStream读取的ObjectInputStream
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\code\\JAVACode\\oos.txt"));

        //Object readObject();//从ObjectInputStream读取一个对象
        Object obj = ois.readObject();
        //向下转型
        Student s = (Student)obj;
        System.out.println(s.getName()+","+s.getAge());

        //释放资源
        ois.close();


    }

用对象序列化一个对象后,假如我们修改了对象所属的类的文件,读取的数据会不会出问题?

,且会抛出InvalidClassException异常 java.io.InvalidClassException:当序列运行时检测到类中以下问题之一时抛出:1)类的串行版本与流中读取的类描述符的类型不匹配;*2)该类包含未知的数据类型;3)该类没有可访问的无参数构造函数;

IO.specialS.Student; local class incompatible:
stream classdesc serialVersionUID = -5898345395929751843,
local class serialVersionUID = 8830609112174703355

如果出了问题,如何解决?
因为序列化运行时与每个可序列化的类关联一个版本号(serialVersionUID),在反序列化过程中使用,以验证序列化对象的发送者和接收者是否加载了序列化兼容的对象的类,如果serialVersionUID不同,反序列化就会报错。 给对象所属的类(可序列化的类)声明一个serialVersionUID:

private static final long serialVersionUID = 42L;(42L可以改)

**强烈建议可序列化的类显示声明serialVersionUID的值
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现?
给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程

 public static void main(String[] args) throws IOException, ClassNotFoundException {
//        write();
        read();
    }
    //反序列化
    private static void read() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\code\\JAVACode\\oos.txt"));
        Object obj = (Student) ois.readObject();
        Student s = (Student) obj;
        System.out.println(s.getName() + "," + s.getAge());
        ois.close();

    }

    //序列化
    private static void write() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\code\\JAVACode\\oos.txt"));
        Student student = new Student("小乔", 18);
        oos.writeObject(student);
        oos.close();
    }

5.4 Properties

在java.util下,Map集合的实现类。Properties可以保存在六种或者从流中加载。

Properties作为集合的特有方法:
Object setProperty(String key, String value);//设置集合的键和值都是String类型,底层调用Hashtable方法put
String getProperty(String key);//使用此属性列表中指定的键搜素属性
Set< String > stringPropertyNames();//从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串

public static void main(String[] args) {
        Properties prop = new Properties();

        //Object setProperty(String key, String value);
        //设置集合的键和值都是String类型,底层调用Hashtable方法put
        prop.setProperty("00001", "小乔");
        prop.setProperty("00002", "大乔");
        prop.setProperty("00003", "周瑜");
        prop.setProperty("00004", "孙策");

        //String getProperty(String key);//使用此属性列表中指定的键搜素属性
        System.out.println(prop.getProperty("00001"));//小乔
        System.out.println(prop.getProperty("000011"));//null

        //Set stringPropertyNames();
        //从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
        Set<String> key = prop.stringPropertyNames();
        for (String k : key) {
//            System.out.println(k);
            String value = prop.getProperty(k);
            System.out.println(k + "," + value);
        }

Properties和IO流结合的方法:
void load(InputStream inStream);//从输入字节流读取属性列表(键和元素对)
void load(Reader reader);//从输入字符流读取属性列表(键和元素对)
void store(OutputStream out, String comments);//将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
void store(Writer writer, String comments); //将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(Reader)方法的格式写入输出字符流

public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        //把集合中的数据保存到文件
//        myStore();
        //把文件中的数据加载到集合
        myLoad();
    }

    private static void myLoad() throws IOException {
        Properties prop = new Properties();

        //void store(OutputStream out, String comments);
        //将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流
        FileReader fw = new FileReader("E:\\code\\JAVACode\\fw.txt");
        prop.load(fw);
        fw.close();

        System.out.println(prop);

    }

    private static void myStore() throws IOException {
        Properties prop = new Properties();

        prop.setProperty("00001", "小乔");
        prop.setProperty("00002", "大乔");
        prop.setProperty("00003", "周瑜");
        prop.setProperty("00004", "孙策");

        // void store(Writer writer, String comments);
        //将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(Reader)方法的格式写入输出字符流
        FileWriter fw = new FileWriter("E:\\code\\JAVACode\\fw.txt");
        prop.store(fw, null);

        fw.close();

    }

你可能感兴趣的:(java,jvm,数据库)