JAVA IO流

1.IO流概述

IO,即in和out,也就是输入和输出,指应用程序和外部设备之间的数据传递,常见的外部设备包括文件、管道、网络连接。

流(Stream),是一个抽象的概念,是指一连串的数据(字符或字节),是以先进先出的方式发送信息的通道。

关于流的特性有下面几点:

1.先进先出:最先写入输出流的数据最先被输入流读取到。
2.顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile除外)
3.只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。

  • IO流的分类
    • 按照数据的流向
      • 输入流:读数据
      • 输出流:写数据
    • 按照数据类型来分
      • 字节流
        • 字节输入流
        • 字节输出流
      • 字符流
        • 字符输入流
        • 字符输出流
  • IO流的使用场景
    • 如果操作的是纯文本文件,优先使用字符流
    • 如果操作的是图片、视频、音频等二进制文件。优先使用字节流
    • 如果不确定文件类型,优先使用字节流。字节流是万能的流 

2.File类

1.File类介绍

  • 它是文件和目录路径名的抽象表示
  • 文件和目录是可以通过File封装成对象的
  • 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的

2.构造方法 

方法名说明
File(String pathname)通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(String parent, String child)从父路径名字符串和子路径名字符串创建新的 File实例
File(File parent, String child)从父抽象路径名和子路径名字符串创建新的 File实例
import java.io.File;

public class FileDemo {
    public static void main(String[] args) {
        //1,public File(String pathname) 	通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
        File f1 = new File("E:\\test\\java.txt");
        System.out.println(f1); //E:\test\java.txt

        //2,public File(String parent,String child) 	从父路径名字符串和子路径名字符串创建新的File实例
        File f2 = new File("E:\\test","java.txt");
        System.out.println(f2); //E:\test\java.txt

        //3,public File(File parent,String child) 	从父抽象路径名和子路径名字符串创建新的File实例
        File f3 = new File("E:\\test");
        File f4 = new File(f3,"java.txt");
        System.out.println(f4); //E:\test\java.txt
    }
}

 3.绝对路径与相对路径

绝对路径与相对路径的区别:

  • 绝对路径::完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如: E:\\test\\java\\java.txt
  • 相对路径: 必须使用取自其他路径名的信息进行解释。例如: test\\java.txt(test表示当前模块)
import java.io.File;

public class FileDemo01 {
    public static void main(String[] args) {
        //这个路径固定不变
        File file=new File("E:\\test\\java.txt");
        //当前项目下的java。txt
        File File2=new File("java.txt");
        //当前项目下 - - - 指定模块下的a.txt
        File File3=new File("filemodule\\java.txt");

    }
}

 4.File创建与删除功能

方法名说明
public boolean createNewFile()当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件
public boolean mkdir()创建由此抽象路径名命名的目录
public boolean mkdirs()创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
public boolean delete()删除此File表示的文件或目录(只能删除空目录)
import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        //需求1: 我要在E:\\test目录 下创建一个文件 java.txt
        File f1 = new File("E:\\test\\java.txt");

        //如果文件不存在,就创建,并返回true; 如果文件存在,就不创建,并返回false
        //1,、public boolean createNewFile() 	当具有该名称的文件不存在时,创建一个新的空文件
        System.out.println(f1.createNewFile()); //true

        //需求2:我要在E:\\test目录下创建一个 目录JavaSE
        File f2 = new File("E:\\test\\JavaSE");

        //2、public boolean mkdir() 	创建此抽象路径命名的目录(只能创建一级目录)
        //如果目录不存在,就创建,并返回true; 如果目录存在,就不创建,并返回false
        System.out.println(f2.mkdir()); //true

        //需求3:我要在E:\\test目录 下创建一个多级目录JavaWEB\\HTML
        File f3 = new File("E:\\test\\JavaWEB\\HTML");
        //3、public boolean mkdirs() 	创建多级目录(建议使用)
        //如果目录不存在,就创建,并返回true; 如果目录存在,就不创建,并返回false
        //System.out.println(f3.mkdir()); //false;mkdir():无法创建多级目录
        //4,public boolean mkdirs()	创建多级目录(建议使用)
        System.out.println(f3.mkdirs()); //true

        //需求4:删除java.txt文件
        //5、public boolean delete()	删除此File表示的文件或目录(只能删除空目录)
        System.out.println(f1.delete()); //true

        //需要5:删除JavaSE
        System.out.println(f2.delete()); //true

        //需求6:先创建java文件,里面创建java.txt文件;并删除java目录
        File f4 = new File("E:\\test\\java");
        f4.mkdir();
        File f5 = new File("E:\\test\\java\\java.txt");
        f5.createNewFile();
        System.out.println(f4.delete()); //false;只能删除空目录
    }
}

 注意:
1.删除不走回收站的
2.如果删除的是文件,那么直接删除,如果删除的是文件夹,那么只能删除空文件夹
3.如果要删除一个有内容的文件,只能先进入这个文件夹,把里面的内容删除完毕,才能删除这个文件夹
简单来说:只能删除文件和空文件夹

5.File类判断和获取功能

判断功能:

方法名说明
public boolean isDirectory()测试此抽象路径名表示的File是否为目录
public boolean isFile()测试此抽象路径名表示的File是否为文件
public boolean exists()测试此抽象路径名表示的File是否存在

获取功能:

方法名说明
public String getAbsolutePath()返回此抽象路径名的绝对路径名字符串
public String getPath()将此抽象路径名转换为路径名字符串
public String getName()返回由此抽象路径名表示的文件或目录的名称
public String[] list()返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles()返回此抽象路径名表示的目录中的文件和目录的File对象数组
import java.io.File;
import java.io.IOException;

public class FileDemo03 {
    public static void main(String[] args) throws IOException {
        //创建file对象
        File f1  = new File("test\\java.txt");

//        public boolean isDirectory() 	判断此抽象路径名表示的File是否为目录
//        public boolean isFile() 	判断此抽象路径名表示的File是否为文件
//        public boolean exists() 	判断此抽象路径名表示的File是否存在
        System.out.println(f1.isDirectory()); //false
        System.out.println(f1.isFile()); //true
        System.out.println(f1.exists()); //true

//        public String getAbsolutePath() 	返回此抽象路径名的绝对路径名字符串
//        public String getPath() 	将此抽象路径名转换为路径名字符串
//        public String getName() 	返回由此抽象路径名表示的文件或目录的名称
        System.out.println(f1.getAbsoluteFile()); //E:\test\test\test\java.txt
        System.out.println(f1.getPath()); //test\java.txt
        System.out.println(f1.getName()); //java.txt
        System.out.println("-----------");

//        public String[] list() 	返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
        File f2 = new File("E:\\test");
        String[] strArray = f2.list();
        for(String s:strArray) {
            System.out.println(s);
            /*java
            java.txt
            test*/
        }

        //public File[] listFiles() 	返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File[] fileArray = f2.listFiles();
        for(File file:fileArray ) {
            /*System.out.println(file);
//            E:\test\java
//            E:\test\java.txt
//            E:\test\test*/

            if(file.isFile()) { //file对象可以调方法
                System.out.println(file); //E:\test\java.txt
            }
        }
    }
}

3.字节流

  • 字节流抽象基类
    • InputStream:这个抽象类是表示字节输入流的所有类的超类
    • OutputStream:这个抽象类是表示字节输出流的所有类的超类
    • 子类名特点:子类名称都是以其父类名作为子类名的后缀

1.字节输出流

  • 父类:OutputStream(抽象类)
  • 子类:FileOutputStream;文件输出流用于将数据写入文件

1.构造方法 

方法名说明
FileOutputStream(String name)(推荐)创建文件输出流以指定名称写入文件
FileOutputStream(File file)创建文件输出流写入以指定的 File对象表示的文件
public FileOutputStream(String file,boolean append)创建一个追加数据的字节输出流管道通向目标文件路径(如果第二个参数为true就追加写入)
public FileOutputStream(File file,boolean append)创建一个追加数据的字节输出流管道通向目标文件对象

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

1、创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件):FileOutputStream(String name) ,(name表示文件路径)
2、调用字节输出流对象的写数据方法:void write(int b)
3、释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源):void close()

范例:

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //创建字节输出流对象
        //FileOutputStream(String name):创建文件输出流以指定的名称写入文件
        FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");
        /*
            做了三件事情:
                A:调用系统功能创建了文件
                B:创建了字节输出流对象
                C:让字节输出流对象指向创建好的文件
         */

        //void write(int b):将指定的字节写入此文件输出流
        fos.write(97);
//        fos.write(57);
//        fos.write(55);

        //最后都要释放资源
        //void close():关闭此文件输出流并释放与此流相关联的任何系统资源。
        fos.close();
    }
}

 2.写入数据的三种方式

方法名说明
void write(int b)将指定的字节写入此文件输出流一次写一个字节数据
void write(byte[ ] b)将b.length字节从指定的字节数组写入此文件输出流一次写一个字节数组数据
void wirte(byte[ ] b,int off,int len)将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流一次写一个字节数组的部分数据
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //一、FileOutputStream(String name) 	创建文件输出流以指定名称写入文件
        FileOutputStream fos = new FileOutputStream("E:\\test\\fos.txt");
        /*源码解析:创建了File对象进行封装
        new File(name)
        FileOutputStream fos = new FileOutputStream(new File("E:\\test\\fos.txt"));*/

        //二、FileOutputStream(File file) 	创建文件输出流写入以指定的 File对象表示的文件
        /*File file = new File("E:\\test\\fos.txt");
        FileOutputStream fos2 = new FileOutputStream(file);*/
//        FileOutputStream fos2 = new FileOutputStream(new File("E:\\test\\fos.txt")); //和上两句相等

        //1、void write(int b) 	将指定的字节写入此文件输出流一次写一个字节数据
        /*fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        fos.write(101);*/
        //abcde

        //2、void write(byte[ ] b) 	将b.length字节从指定的字节数组写入此文件输出流一次写一个字节数组数据
        /*byte[] bys = {97,98,99};
        fos.write(bys); //abc*/
        //byte[] getBytes():返回字符串对应的字节数组
        byte[] bys = "abc".getBytes();
//        fos.write(bys); //abc

        //3,void wirte(byte[ ] b,int off,int len)
        //将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流一次写一个字节数组的部分数据
        fos.write(bys,1,2); //bc;从索引1开始写两个
        fos.close();
    }
}

3.字节输出流换行和追加写入

  • 字节流写数据如何实现换行

    • windows:\r\n
    • linux:\n
    • mac:\r 
  • 字节流写数据如何实现追加写入

    • public FileOutputStream(String name,boolean append)
    • 创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo03 {
    public static void main(String[] args) throws IOException {
        //public FileOutputStream(String file,boolean append) 	创建一个追加数据的字节输出流管道通向目标文件路径
        FileOutputStream fos = new FileOutputStream("E:\\test\\fos.txt",true);

        for(int i=0;i<4;i++) {
            fos.write("hello".getBytes()); //hellohellohellohello
            fos.write("\r\n".getBytes());
            /*第一次执行
            hello
            hello
            hello
            hello*/
            /*第二次执行
            hello
            hello
            hello
            hello
            hello
            hello
            hello
            hello*/
        }
        fos.close();
    }
}

 4.字节流写数据加异常处理

  • finally:在异常处理时提供finally块来执行所有清除操作。比如说O流中的释放资源
  • 特点:被finally控制的语句一定会执行,除非JVM退出

格式:try-catch-finally 

try{
	可能出现异常的代码;
}catch(异常类名 变量名){
	异常的处理代码;
}finally{
	执行所有清除操作;
}

代码:

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo03 {
    public static void main(String[] args) {
        FileOutputStream fos =null; //初始化
        try {
// 1,测试地址错误           fos = new FileOutputStream("Z:\\test\\fos.txt");
            fos = new FileOutputStream("E:\\test\\fos.txt");
            fos.write("hello".getBytes());
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            //1,NullPointerException;当文件地址错误时,fos还是为null,就不需要释放内存,所以需要加个判断fos是否为null的判断
            if(fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 2.字节输入流

  • 父类:InputStream(抽象类)

  • 子类:FileInputStream(实现类:从文件系统中的文件获取输入字节)

 1.构造方法

方法名说明
public FileInputStream(File path)创建一个字节输入流管道与源文件对象接通
public FileInputStream(String pathName)创建一个字节输入流管道与文件路径对接

 2.读取方法

方法名说明
public int read()每次读取一个字节返回!读取完毕会返回 -1
public int read(byte[] buffer)从字节输入流中读取字节到字节数组中去,返回读取的字节数量,没有字节可读返回 -1
  • 使用字节输入流读数据的步骤
    • 1、创建字节输入流对象
    • 2、调用字节输入流对象的读数据方法
    • 3、释放资源
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 1、创建字节输入流对象
        FileInputStream fis = new FileInputStream("D:\\test\\fos.txt");

        //2、调用字节输入流对象的读数据方法
        //int read():从该输入流读取一个字节数据
        //第一次读取数据
        /*int by = fis.read();
        System.out.println(by); //97,表示a
        System.out.println((char)by); //a

        //第二次读取数据
        by = fis.read();
        System.out.println(by); //98
        System.out.println((char)by); //b

        //再多读取两次
        by = fis.read();
        System.out.println(by); //-1,表示没有数据了
        by = fis.read();
        System.out.println(by); //-1*/

        //循环改进
        /*int by = fis.read();
        while(by != -1) {
            System.out.print((char)by); //ab
            by = fis.read();
        }*/

        //优化循环
        int by;
        //1、先做了读数据fis.read();2、赋值by=fis.read();3、与by 与 -1比较
        while((by=fis.read()) != -1) {
            System.out.print((char)by); //ab
        }
        
        //3、释放资源
        fis.close();
    }
}

按字节数组读取

import java.io.FileInputStream;
import java.io.IOException;

public class CopyTxtDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:\\test\\fos.txt");

        byte[] bys = new byte[1024]; //1024及其整数倍
        int len;
        while((len=fis.read(bys)) != -1) {
            System.out.println(new String(bys,0,len));
            /*ab
            cd*/
        }
        fis.close();
    }
}

案例:字节流复制文本文件

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyTxtDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:\\test\\fos.txt");

        FileOutputStream fos = new FileOutputStream("D:\\test\\Demo\\fos.txt");
        //读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
        int by;
        while((by=fis.read()) != -1) {
            fos.write(by);
        }
        //释放资源
        fos.close();
        fis.close();
    }
}

案例:字节流复制图片

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyPngDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:\\test\\1.png");

        FileOutputStream fos = new FileOutputStream("D:\\test\\Demo\\1.png");

        byte[] bys = new byte[1024];
        int len;
        while((len=fis.read(bys)) != -1) {
            fos.write(bys,0,len);
        }

        fos.close();
        fis.close();
    }
}

3.字节缓冲流

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

1.构造方法

方法名说明
BufferedOutputStream(OutputStream out)创建字节缓冲输出流对象
BufferedInputStream(InputStream in)创建字节缓冲输入流对象
import java.io.*;

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

        //字节缓冲输出流:BufferedOutputStream(OutputStream out)
        /*FileOutputStream fos = new FileOutputStream("E:\\test\\fos.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);*/

        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\test\\fos.txt"));

        //写数据
        bos.write("hello\r\n".getBytes());
        bos.write("java\r\n".getBytes());

//        hello
//        java
        bos.close();

        //字节缓冲输入流:BufferedInputStream(InputStreamin)
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\fos.txt"));

        int by;
        while((by=bis.read()) != -1) {
            System.out.print((char)by);
//            hello
//            java
        }

        bis.close();
    }
}

 案例:字节流复制视频

import java.io.*;
public class CopyAviDemo {
    public static void main(String[] args) throws IOException {
        //记录开始时间
        long startTime = System.currentTimeMillis();

        //复制视频
//        method1();
//        method2();
//        method3();
        method4();

        //记录结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("共耗时:" + (endTime - startTime) + "毫秒");
    }

    //字节缓冲流一次读写一个字节数组
    public static void method4() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\复制视频.avi"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\test\\Demo\\复制视频.avi"));

        byte[] bys = new byte[1024];
        int len;
        while ((len=bis.read(bys))!=-1) {
            bos.write(bys,0,len);
        }

        bos.close();
        bis.close();
    }

    //字节缓冲流一次读写一个字节
    public static void method3() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\test\\复制视频.avi"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\test\\Demo\\复制视频.avi"));

        int by;
        while ((by=bis.read())!=-1) {
            bos.write(by);
        }

        bos.close();
        bis.close();
    }


    //基本字节流一次读写一个字节数组
    public static void method2() throws IOException {
        //E:\\itcast\\字节流复制图片.avi
        //模块目录下的 字节流复制图片.avi
        FileInputStream fis = new FileInputStream("D:\\test\\复制视频.avi");
        FileOutputStream fos = new FileOutputStream("D:\\test\\Demo\\复制视频.avi");

        byte[] bys = new byte[1024];
        int len;
        while ((len=fis.read(bys))!=-1) {
            fos.write(bys,0,len);
        }

        fos.close();
        fis.close();
    }

    //基本字节流一次读写一个字节
    public static void method1() throws IOException {
        //E:\\itcast\\字节流复制图片.avi
        //模块目录下的 字节流复制图片.avi
        FileInputStream fis = new FileInputStream("D:\\test\\复制视频.avi");
        FileOutputStream fos = new FileOutputStream("D:\\test\\Demo\\复制视频.avi");

        int by;
        while ((by=fis.read())!=-1) {
            fos.write(by);
        }

        fos.close();
        fis.close();
    }
}

4.字符流

  • 字符流抽象基类
    • Reader:字符输入流的抽象类
    • Writer:字符输出流的抽象类

1.字符流概述

由于字节流操作中文不是特别的方便,所以Java就提供字符流

字符流 = 字节流 + 编码表

汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

编码表

是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等

ASCII字符集:

lASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)

GBXXX字符集:

GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等

Unicode字符集:

UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用 中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码

编码规则:

128个US-ASCII字符,只需一个字节编码

拉丁文等字符,需要二个字节编码

大部分常用字(含中文),使用三个字节编码

其他极少使用的Unicode辅助字符,使用四字节编码

2.字符串中的编码解码问题

方法名说明
byte[] getBytes()使用平台的默认字符集将该 String编码为一系列字节
byte[] getBytes(String charsetName)使用指定的字符集将该 String编码为一系列字节
String(byte[] bytes)使用平台的默认字符集解码指定的字节数组来创建字符串
String(byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class StringDemo {
    public static void main(String[] args) throws  UnsupportedEncodingException {
        //定义一个字符串
        String s = "中国";

        //byte[] bys = s.getBytes(); //[-28, -72, -83, -27, -101, -67]
        //byte[] bys = s.getBytes("UTF-8"); //[-28, -72, -83, -27, -101, -67]
        byte[] bys = s.getBytes("GBK"); //[-42, -48, -71, -6]
        System.out.println(Arrays.toString(bys));

        //String ss = new String(bys);
        //String ss = new String(bys,"UTF-8");
        String ss = new String(bys,"GBK");
        System.out.println(ss);
    }
}

 3.字符流中的编码解码问题

  • InputStreamReader:是从字节流到字符流的桥梁

    ​ 它读取字节,并使用指定的编码将其解码为字符

    ​ 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集

  • OutputStreamWriter:是从字符流到字节流的桥梁

    ​ 是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节

    ​ 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集

 4.构造方法

方法名说明
InputStreamReader(InputStream in)使用默认字符编码创建InputStreamReader对象
InputStreamReader(InputStream in,String chatset)使用指定的字符编码创建InputStreamReader对象
OutputStreamWriter(OutputStream out)使用默认字符编码创建OutputStreamWriter对象
OutputStreamWriter(OutputStream out,String charset)使用指定的字符编码创建OutputStreamWriter对象
import java.io.*;

public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {
//        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\test\\fos.txt"));
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\test\\fos.txt"),"GBK");
        osw.write("中国");
        osw.close();

//1,        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\test\\fos.txt"));
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\test\\fos.txt"),"GBK");
        int ch;
        while((ch= isr.read()) !=-1) {
            System.out.print((char)ch); //1:�й�;2:中国,因为第二次和编码格式GBK一样
        }
        isr.close();
    }
}

 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)写一个字符串的一部分

 关闭和刷新的方法

方法名说明
flush()刷新流,之后还可以继续写数据
close()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\test\\fos.txt"));

        //1,void write(int c) 	写一个字符
        /*osw.write(97);
        osw.write(98);
        //ab
        //void flush():刷新流
        osw.flush();*/

        //2,void write(char[ ] cbuf) 	写一个字符数组
        /*char[] chs = {'a','b','c'};
//        osw.write(chs);
        //abc

        //3,void write(char[ ] cbuf,int off,int len) 	写一个字符数组的一部分
        osw.write(chs,1, 2); //bc,1索引开始,写两个*/

        //4,void write(String str) 	写一个字符串
//        osw.write("abcef"); //abcef

        //5,void write(String str,int off,int len) 	写一个字符串的一部分
        osw.write("abcdef",0, "abcdef".length()); //abcdef
        //osw.write("abcde", 1, 3);//bcd
        osw.close();
    }
}

6.字符输出流

方法名说明
int read()一次读一个字符数据
int read(char[] cbuf)一次读一个字符数组数据
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\test\\fos.txt"));

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

        //2,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();
    }
}

 案例:字符流复制java文件

import java.io.*;

public class CopyJavaDemo {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符输入流对象
        FileReader fr = new FileReader("D:\\test\\Demo.java");
        //根据目的地创建字符输出流对象
        FileWriter fw = new FileWriter("D:\\test\\Demo\\Demo.java");

        //读写数据,一次一个
        /*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);
        }

        fw.close();
        fr.close();
    }
}

 7.字符缓冲流

BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途
BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途

1.构造方法

方法名说明
BufferedWriter(Writer out)创建字符缓冲输出流对象
BufferedReader(Reader in)创建字符缓冲输入流对象
import java.io.*;

public class BufferedStreamDemo01 {
    public static void main(String[] args) throws IOException {
        //2,BufferedWriter(Writer out)
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\test\\fos.txt"));
        bw.write("hello\r\n");
        bw.write("world\r\n");
        bw.close();

        //1,BufferedReader(Reader in)
        BufferedReader br = new BufferedReader(new FileReader("D:\\test\\fos.txt"));
        //一次读一个字符数据
        /*int ch;
        while((ch=br.read()) != -1) {
            System.out.print((char)ch);
        }
        br.close();*/

        //一次读一个字符数组
        char[] chs = new char[1024];
        int len;
        while((len=br.read(chs)) != -1) {
            System.out.println(new String(chs,0,len));
        }
        br.close();
    }
}

 2.字符缓冲流特有功能

BufferedWriter:

方法名说明
void newLine()写一行行分隔符,行分隔符字符串由系统属性定义

BufferedReader:

方法名说明
String readLine()读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null

import java.io.*;

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        //创建字符缓冲流输出流
        /*BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\test\\fos.txt"));

        for(int i=0;i<5;i++) {
            bw.write("hello"+i);
//            bw.write("\r\n");
            //2,void newLine():写一行行分隔符, 行分隔符字符串由系统属性定义
            bw.newLine();
            bw.flush();
        }
        bw.close();*/

        //创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("D:\\test\\fos.txt"));
        //2,public String readLine():读一行文字
        String line;
        while((line=br.readLine()) != null) {
            System.out.println(line);
            /*
            hello0
            hello1
            hello2
            hello3
            hello4*/
        }
        br.close();
    }
}

案例:字符缓冲流特有功能复制文件

package test;

import java.io.*;

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        //根据数据源创建字符缓冲流输入对象
        BufferedReader br = new BufferedReader(new FileReader("E:\\test\\fos.txt"));
        //根据数据源创建字符缓冲流输出对象
        BufferedWriter bw = new BufferedWriter(new FileWriter(("E:\\test\\Demo\\copy.txt")));

        String line;
        while((line=br.readLine()) !=null){
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        bw.close();
        br.close();
    }
}

 5.IO流小结

6.特殊流

1.标准输入输出流

1.标准输入流

System类中有两个静态的成员变量:
public static final InputStream in:标准输入流,通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
public static final PrintStream out:标准输出流,通常该流对应于显示输出或由主机环境或用户指定的另一个输入源

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class SystemInDemo {
    public static void main(String[] args) throws IOException {
        //public static final InputStream in:标准输入流
//        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);

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.println("请输入一个字符串:");
        String line = br.readLine();
        System.out.println("你输入的字符串是:" + line);

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

        //自己实现键盘录入数据太麻烦了,所以Java就提供了一个类供我们使用
       // Scanner sc = new Scanner(System.in);
    }
}

2.标准输出流

  • 输出语句的本质:是一个标准的输出流

    • PrintStream ps = System.out;
    • PrintStream类有的方法,System.out都可以使用 

import java.io.PrintStream;

public class SystemOutDemo {
    public static void main(String[] args) {
        //public static final PrintStream out:标准输出流
        PrintStream ps = System.out;

        //能够方便地打印各种数据值
//        ps.print("hello");
//        ps.print(100);

//        ps.println("hello");
//        ps.println(100);

        //System.out的本质是一个字节输出流
        System.out.println("hello");
        System.out.println(100);

        System.out.println();
//        System.out.print();
    }
}

2.打印流

  • 打印流分类
    • 字节打印流:PrintStream
    • 字符打印流:PrintWriter
  • 打印流特点
    • 只负责输出数据,不负责读取数据
    • 有自己特有方法

1.字节打印流

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

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

可以改变输出语句的目的地

public static void setOut(PrintStream out):重新分配“标准”输出流

import java.io.IOException;
import java.io.PrintStream;

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
        //PrintStream(String fileName):使用指定的文件名创建新的打印流
        PrintStream ps = new PrintStream("D:\\test\\Demo.java");

        //写数据
        //字节输出流有的方法
//        ps.write(97);

        //使用特有方法写数据
//        ps.print(97);
//        ps.println();
//        ps.print(98);
        ps.println(97);
        ps.println(98);

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

2.字符打印流

构造方法 :

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

public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
        //PrintWriter(String fileName) :使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新
//        PrintWriter pw = new PrintWriter("D:\\test\\java.txt");

//        pw.write("hello");
//        pw.write("\r\n");
//        pw.flush();
//        pw.write("world");
//        pw.write("\r\n");
//        pw.flush();

//        pw.println("hello");
        /*
            pw.write("hello");
            pw.write("\r\n");
         */
//        pw.flush();
//        pw.println("world");
//        pw.flush();

        //PrintWriter(Writer out, boolean autoFlush):创建一个新的PrintWriter
        PrintWriter pw = new PrintWriter(new FileWriter("D:\\\\test\\\\java.txt"),true);
//        PrintWriter pw = new PrintWriter(new FileWriter("D:\\test\\java.txt"),false);

        pw.println("hello");
        /*
            pw.write("hello");
            pw.write("\r\n");
            pw.flush();
         */
        pw.println("world");

        pw.close();
    }
}

3.复制Java文件打印流改进版

import java.io.*;

public class CopyJavaDemo {
    public static void main(String[] args) throws IOException {
        /*
        //根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("D:\test\Demo.java"));
        //根据目的地创建字符输出流对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:\test\Demo\Demo.java"));

        //读写数据,复制文件
        String line;
        while ((line=br.readLine())!=null) {
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        //释放资源
        bw.close();
        br.close();
        */

        //根据数据源创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("D:\\test\\Demo.java"));
        //根据目的地创建字符输出流对象
        PrintWriter pw = new PrintWriter(new FileWriter("D:\\test\\Demo\\Demo.java"),true);

        //读写数据,复制文件
        String line;
        while ((line=br.readLine())!=null) {
            pw.println(line);
        }

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

 3.对象操作流

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

  • 要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:

    • 对象序列化流: ObjectOutputStream
    • 对象反序列化流:ObjectInputStream 

1.对象序列化流

将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象

构造方法:

方法名说明
ObjectOutputStream(OutputStream out)创建一个写入指定的OutputStream的ObjectOutputStream

序列化对象的方法

方法名说明
void writeObject(Object obj)将指定的对象写入ObjectOutputStream

学生类:

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类 

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\test\\java.txt"));

        //创建对象
        Student s = new Student("蔡徐坤",25);

        //void writeObject(Object obj):将指定的对象写入ObjectOutputStream
        oos.writeObject(s);

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

注意:

一个对象要想被序列化,该对象所属的类必须必须实现Serializable接口

Serializable是一个标记接口,实现该接口,不需要重写任何方法

2.对象反序列化流

ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象

构造方法

方法名说明
ObjectInputStream(InputStream in)创建从指定的InputStream读取的ObjectInputStream

反序列化对象的方法 

方法名说明
Object readObject()从ObjectInputStream读取一个对象
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

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

        //Object readObject() 	从ObjectInputStream读取一个对象
        Student s = (Student) ois.readObject();
        System.out.println(s.getName()+","+s.getAge()); 
        ois.close();
    }
}

 3.serialVersionUID&transient

 范例:

学生类:

import java.io.Serializable;

public class Student implements Serializable {
    private static final long serialVersionUID = 42L;
    private String name;
    //    private int age;
    private transient int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

//    @Override
//    public String toString() {
//        return "Student{" +
//                "name='" + name + '\'' +
//                ", age=" + age +
//                '}';
//    }
}

测试类:

import java.io.*;

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
//       write();
        read();
    }

    //反序列化
    private static void read() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\test\\java.txt"));
        Object obj = 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("D:\\test\\java.txt"));
        Student s = new Student("林青霞", 30);
        oos.writeObject(s);
        oos.close();
    }
}

4.Properties

1.Properties的使用

  • 是一个Map体系的集合类
  • Properties可以保存到流中或从流中加载
  • 属性列表中的每个键及其对应的值都是一个字符串
import java.util.Properties;
import java.util.Set;

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

        //存储元素
        prop.put("001","喜羊羊");
        prop.put("002","懒羊羊");
        prop.put("003","沸羊羊");

        Set<Object> keySet = prop.keySet();
        for(Object key:keySet) {
            Object value = prop.get(key);
            System.out.println(key+","+value);
        }
    }
}

2.Properties作为Map集合的特有方法

方法名说明
Object setProperty(String key, String value)设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
String getProperty(String key)使用此属性列表中指定的键搜索属性
Set stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
import java.util.Properties;
import java.util.Set;

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

        //1,Object setProperty(String key, String value) 	设置集合的键和值,都是String类型, 底层调用Hashtable方法 put
        prop.setProperty("001","喜羊羊");
        /*
        public synchronized Object setProperty(String key, String value) {
            return put(key, value);
        }*/
        prop.setProperty("002","懒羊羊");
        prop.setProperty("003","沸羊羊");

        //String getProperty(String key) 	使用此属性列表中指定的键搜索属性
        System.out.println(prop.getProperty("003")); //沸羊羊
        System.out.println(prop.getProperty("004")); //null

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

3Properties与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)方法的格式写入输出字符流

import java.io.*;
import java.util.Properties;

public class PropertiesDemo02 {
    public static void main(String[] args) throws IOException{
        //把集合中的数据保存到文件
        myStore();

        //把文件中的数据保存到集合
        myLood();
    }

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

        FileReader fr = new FileReader("D:\\test\\java.txt");
        //void load(Reader reader)
        prop.load(fr);
        fr.close();

        System.out.println(prop); //{003=沸羊羊, 002=懒羊羊, 001=喜羊羊}
    }

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

        prop.setProperty("001", "喜羊羊");
        prop.setProperty("002", "懒羊羊");
        prop.setProperty("003", "沸羊羊");

        //void store(Writer writer, String comments)
        FileWriter fw = new FileWriter("D:\\test\\java.txt");
        prop.store(fw,null);//第二个值为注释
        fw.close();
    }
}

.


 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值