【JAVASE(10)】JAVASE学习--文件(File)类与IO流篇(1)

        java文件(File)类与IO流

文件(File)类:
    一、文件(File)类的定义:
        java.io.file文件和目录路径及名称的抽象表示形式;
        java把电脑中的文件和文件夹(目录)封装为了一个file类,可以使用file类对文件和文件夹进行操作;
        File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)

        说明:
            1.File类声明在java.io包下
            2.File类中涉及关于文件或文件目录的创建、删除、重命名、修改时间、文件大小,判断文件是否存在等方法,并未涉及到写入或读取文件内容的操作,如果需要读取或写入文件内容,必须使用IO流来完成
            3.file类是一个与操作系统无关的类,任何操作系统都可以使用这个类中方法
            4.后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的“终点”
            5.几个关键词:
                file:文件,与文件相关的操作
                directory:文件夹/目录,与文件夹/目录相关的操作
                path:路径,与路径相关操作

        
        注:
            路径不区分大小写;路径中的文件名称分隔符Windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通反斜杠

        tip:学习一个类:
            首先看此类中是否有静态成员。因为静态成员可以直接通过类名来访问,
            第二个学习类中的构造方法,通过构造方法可以创建对象,创建完对象后,通过对象可以直接访问成员方法


    二、创建File类的实例:
        构造器一(此时不对应硬盘中的文件,此时仅仅只是内存中的一个对象,并不涉及对文件中的数据进行增删改查等操作):

public File(String pathname):

参数:
    String pathname:字符串的路径名称
    路径可以是文件结尾,也可以是文件夹结尾
    路径可以是相对路径,也可以是绝对路径
    路径可以是存在,有可以是不存在
    创建File对象只是把字符串路径封装为File对象,不考虑路径的真假情况

                作用:
                    通过将给定路径名字字符串转换为抽象路径名来创建一个新File实例。即以pathname为路径创建File对象,可以是绝对路径或相对路径,若pathname是相对路径,则默认的当前路径在系统属性user.dir中存储

                    >绝对路径:是一个完整路径。是一个固定的路径,从盘符(C:,D:)开始。即包含盘符在内(C:\\)的文件或文件目录的路径
                    >相对路径:是一个简化路径,相对指的是相对于当前项目的根目录是相对于某个位置开始。即相对于某个路径下,指明的路径
                    >分隔符:
                        windows和DOS下默认使用“\”
                        UNX、Linux和URL下默认使用“/”
                        为了适应不同平台下的分隔符,java提供了

public static final String separator类,对程序中的路径进行动态分割;

static String separator
    与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串;

static char separatorChar
    与系统有关的默认名称分隔符。

static String pathSeparator
    与系统有关的路径分隔符,为了方便,它被表示为一个字符串

static char pathSeparatorChar
    与系统有关的路径分隔符


实例{
灵活:"G:"+File.separator+"WioJiaQi"+File.separator+"javabase"
    new File("d:\\workspace\\One.txt");
    new File("d:"+File.separator+"workspace"+File.separator+"One.txt");
    new File("d:/workspace/One.txt");
}

        构造器二(此时不对应硬盘中的文件,此时仅仅只是内存中的一个对象,并不涉及对文件中的数据进行增删改查等操作):

public File(String parent,String child):
    以parent为父路径,child为子路径创建File对象,
    这个file对象可以是一个文件目录,也可以是一个文件。
    即由parent路径名字符串和child路径名字符串创建一个File实例。

    参数:把路径分成了两部分
        String parent:父路径
        String child:子路径

                好处:
                    父路径和子路径可以单独书写,使用起来非常灵活:父子路径都可以变换

        构造器三(此时不对应硬盘中的文件,此时仅仅只是内存中的一个对象,并不涉及对文件中的数据进行增删改查等操作):

public File(File parent,String child):
    根据一个File对象和子文件路径创建File对象,
    指定目录下创建指定目录或文件。
    即由parent路径名字符串和child路径名字符串创建一个File实例

    参数:把路径分成了两部分
        String parent:父路径
        String child:子路径


                好处:
                    父路径和子路径可以单独书写,使用起来非常灵活:父子路径都可以变换
                    父路径是File类型,可以使用file的方法对路径进行一些操作,再使用路径创建对象


    三、File类的常用方法:       

        1.文件类的获取功能

public String getAbsolutePath():
    获取绝对路径。即返回此File的绝对路径名字符串
    获取构造方法中传递的路径
    无论路径是绝对路径还是相对路径,
    getAbsolutePath方法返回都是绝对路径

public String getPath():
    获取路径。将此File转换为路径字符串
    获取构造方法中传递的路径
    toString()调用的是getPath方法
        源码:
            public String toString(){
                return getPath();
            }

public String getName():
    获取名称。返回由此File表示的文件或目录的名称。
    获取的就是构造方法传递路径的结尾部分(文件/文件夹)

public String getParent():
    获取上层文件目录路径。若无,返回null;

public long length():
    获取文件长度(即:字节数)。不能获取目录长度。
    返回由此File表示的文件长度
    获取的是构造方法指定的文件的大小,以字节为单位
    注:
        文件夹无大小概念,不能获取文件夹的大小
        若构造方法中给出的路径不存在,则length方法返回0

public long lastModified():
    获取最后一次修改时间,毫秒值

        2.适用于文件目录

public String[] list():
    获取指定目录下的所有文件或文件目录的名称数组,
    要求文件或目录存在,否则报错。返回一个String数组,
    表示该目录中的所有子文件或目录。遍历构造方法中给出的目录,
    会获取目录中所有文件/文件夹的名称,
    把获取到的多个名称存储到一个String类型数组中能够访问隐藏文件夹

public File[] listFiles():
    获取指定目录下的所有文件或文件目录的File数组,
    若直接输出则输出包含绝对路径的文件名称,返回一个file数组,
    表示该目录中的所有子文件或目录。遍历构造方法中给出的目录,
    会获取目录中所有文件/文件夹的名称,把文件/文件夹封装为File对象,
    多个file对象存储到file数组中
        注:
            list方法和listFiles方法遍历的是构造方法中给出的目录
            若构造方法中给出的目录的路径不存在,会抛出空指针异常
            若构造方法中给出的路径不是一个目录,会抛出空指针异常

public boolean renameTo(File dest):
    把文件重新命名为指定的文件路径
        如file1.renameTo(file2)为例子:要想保证返回是true,
        需要保证file1在硬盘中是存在的,且file2不能在硬盘中存在

        3.文件类的功能判断

public boolean isDirectory():
    判断是否是目录文件。此File表示的是否为目录
    用于判定构造方法中给定路径是否以文件夹结尾
        是:true
        否:false

public boolean isFile():
    判断是否是文件。此File表示的是否为文件
    用于判定构造方法中给定路径是否以文件夹结尾
        是:true
        否:false
    注:
        电脑硬盘中只有文件,文件夹,两个方法互斥
        这两个方法使用前提,路径必须存,在否则均返回false

public boolean exists():
    判断是否存在。此File表示的文件或者目录是否存在
    用于判断构造方法中的路径是否存在
        存在:true
        不存在:false

public boolean canRead():
    判断是否可读

public boolean canWrite():
    判断是否可写

public boolean iSHidden():
    判断是否隐藏

        4.文件的创建:

public boolean createNewFile():
    创建文件。若文件存在则不创建,并且返回false;
    当且仅当具有该名称的文件夹不存在时,创建一个新的空文件夹。
    创建文件的路径和名称在构造方法中给出(构造方法的参数)

    返回值:布尔值
        true:文件不存在,创建文件,返回true
        false:文件存在,不会创建文件夹,返回false

    注:
        此方法只能创建文件,不能创建文件夹
        创建文件的路径必须存在,否则会抛出异常
        public boolean createNewFile() throws IOException
        createNewFile()申明抛出IOException异常,
            调用此方法必须处理此异常,
            要么throws,要么try...catch

public boolean mkdir():
    创建文件目录。若此文件目录存在,就不创建,
    若此文件目录的上层目录不存在,也不创建。
    创建由此File表示的目录(单级文件夹)。
    创建文件夹的路径和名称在构造方法中给出(构造方法的参数)

    返回值:布尔值
        true:文件夹不存在,创建文件夹,返回true
        false:文件夹存在,不会创建文件夹,返回false;
            构造方法中给出的路径不存在,返回false

    注:
        此方法只能创建文件夹,不能创建文件

public boolean mkdirs():
    创建文件目录,若上层目录不存在,一并创建。
    创建由此File表示的目录,包括任何必须但不存在的父目录(单级,多级均可以)。
    创建文件夹的路径和名称在构造方法中给出(构造方法的参数)

    返回值:布尔值
        true:文件夹不存在,创建文件夹,返回true
        false:文件夹存在,不会创建文件夹,返回false;
            构造方法中给出的路径不存在,返回false

    注:
        此方法只能创建文件夹,不能创建文件

         5.文件类的删除功能:

 public boolean delete():
    删除指定文件或文件夹,要删除一个文件目录,
    则必须确保该文件目录内部包含任何文件或文件目录。
    删除由此File表示的文件或者目录。
    此方法可以删除构造方法中给出的文件/文件夹

    返回值:布尔值
        true:文件/文件夹删除成功,返回true
        false:文件夹中有内容不会删除,返回false;
            构造方法中路径不存在,返回false
    注:
        delete方法直接走硬盘删除,不走回收站删除,删除需谨慎


    四、关于过滤器FileFilter:
        创建过滤器FileFilter的实现类,重写过滤方法accept,定义过滤规则
        过滤规则:在accept方法中,判断File对象是否以指定后缀结尾,是返回true,不是返回false
        文件搜索,只要指定后缀结尾的文件
        可以使用过滤器来实现:
            在File类中有两个和ListFiles重载的方法,方法的参数传递的就是过滤器
            File[] listFiles(FileFilter filter)
                java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器;作用是用于过滤文件(File对象)
                抽象方法:用于过滤文件的方法:

 boolean accept(File pathname):
    测试指定抽象路径名是否应该包含在某个路径名列表中

    参数:
        File pathname:使用ListFiles方法遍历目录,得到每一个文件对象

            File[] listFiles(FilenameFilter filter)
                java.io.FilenameFilter接口:此接口的类实例可用于过滤文件名;作用:用于过滤文件名
                抽象方法:用来过滤文件的方法

boolean accept(File dir,String name):
    测试文件是否应该包含在某一文件列表中
    
    参数:
        File dir:构造方法中传递的被遍历的目录
        String name:使用ListFiles方法遍历目录,获取每一个文件/文件夹的名称

            注意:
                两个过滤器接口是没有实现类的,需要自己写实现类,重写过滤方法accept,在方法中自己定义过滤的规则


        过滤器原理:
                必须明确两件事情:

                        1. 过滤器中的accept方法是谁调用的;2.accept方法的参数pathname是什么

        listFiles干了3件事:

                                1.listFiles方法会对构造方法中传递的目录进行遍历,获取目录中的每一个文件/文件夹-->封装为File对象
                                2.listFiles方法会调用参数传递的过滤器中的方法accept
                                3.listFiles方法会把遍历得到的每一个File对象,传递过accept方法的参数pathname
        accept方法的返回值是一个布尔值:

                true:就会把传过去的File对象保存在File数组中
                false:就不会把传过去的File对象保存在File数组中

IO流
    一、IO流概述:
        I:input 输入(读取),把硬盘中的东西放到内存中
        O:output 输出(写入),把内存中的东西写入到硬盘中
        流:数据(字符,字节)1个字符=2个字节,1个字符=8个二进制位
        字节流:字节输入流InputStream,字节输出流:OutputStream
        字符流:字符输入流:Reader,字符输出流:Writer
        一切皆为字节:计算机中的所有文件数据(如MP4,mp3等)在存储时,都是以二进制数字的形式保存。即计算机中任何存储文件均是以二进制字节存储。因此字节流可以传输任何文件数据


    二、IO流的分类:
        1.四种分类方式:
            java的io流是以程序(内存)为视角,即文件到程序(内存)的方向即为输入

            io流以操作数据单位的不同分为:
                字节流(8bit){适合用于图片,视频等非文本二进制数据},字符流(16bit){适合用于处理文本char型数据}

            io流以角色分:

结点流{作用于文件上的流:
    文件流(结点流):
        FileInputStream,
        FileOutputStream,
        FileReader,
        FileWriter
}

处理流{作用于已经存在流的流,除4个结点流外的流:

    缓冲流:
        BufferedInputStream,
        BufferedOutputStream,
        BufferedReader,
        BufferedWriter

    转换流:
        InputStreamReader,
        OutputStreamWriter(属于字符流)

    对象流:
        ObjectInputStream,
        ObjectOutputStream
    等等
}


            流的分类(只看后缀名称):
            抽象基类    字节流     字符流
            输入流    InputStream   Reader
            输出流    OutputStream  Writer


    三、流的体系结构:

抽象基类:
    InputStream、OutputStream、Reader、Writer

结点流:
    FileInputStream(read(byte[] buffer))、
    FileOutputStream(write(byte[] buffer,0,len))、
    FileReader(read(char[] cbuf))、
    BufferedWriter(write(char[] buffer,0,len))
    
缓冲流(处理流中的一种,内置了flush()方法,不必显式调用):
    BufferedInputStream(read(byte[] buffer))、
    BufferedOutputStream(write(byte[] buffer,0,len))、
    BufferedReader(read(char[] cbuf))、
    BufferedWriter(write(char[] buffer,0,len))


    四、结点流的使用:

        1.流的使用步骤:
            1、File类的实例化
            2、流的实例化,将File的实例作为流的构造器参数
            3、读入/写出的操作,造相应的字符/字节数组
            4、资源的关闭
            5、异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try...catch...finally结构处理


        2.文件字符流/文件字节流:

            输入操作:
                从硬盘的某个文件中将数据以字符/字节为单位读入到内存中

            读取数据的原理(硬盘-->内存)
                java程序-->JVM-->OS-->OS读取数据的方法-->读取文件

            FileReader/FileInputStream:
                    java.io.reader:字符输入流,是字符输入流的顶层父类,定义了一些共性的成员方法,是一个抽象类                       

                        共性成员方法:

int read():
    读取单个字符并返回
    FileReader(字符流状态)从硬盘中读入文件中的一个字符到内存中,若达到文件末尾,返回-1
    FileInputStream(字节流状态)从硬盘中读入文件中的一个字节到内存中,若达到文件末尾,返回-1


int read(char/byte[] c/bbuf):
    一次读取多个字符,将字符读入数组
    FileReader(字符流状态)返回每次读入cbuf数组中的字符的个数,若达到文件末尾则返回-1
    FileInputStream(字节流状态)返回每次读入cbuf数组中的字节的个数,若达到文件末尾则返回-1

void close:
    关闭该流并释放与之相关的所有资源
    在关闭前先判断关闭的流是否为空。


                    java.io.FileReader extends InputStreamReader extends Reader
                        FileReader:
                            文件字符输入流

                        作用:
                            把硬盘文件中的数据以字符的方式读取到内存中

                        构造方法:

FileReader(String fileName)
FileReader(File file)
    参数:读取文件的数据源
        String fileName:文件的路径
        File file:一个文件


                            FileReader构造方法的作用:
                                1.创建一个FileReader对象
                                2.会把FileReader对象指向要读取的文件

                        字符输入流的使用步骤:
                            1.创建FileReader对象,构造方法中绑定要读取的数据源
                            2.使用FileReader对象中的方法read读取文件
                            3.释放资源

                        string类的构造方法

String(char[] value)
    把字符数组转换成字符串

String(char[] value,int offset,int count)
    把字符数组一部分转换为字符串,offset:数组开始索引;count:转换的个数

                    java.io.InputStream:字节输入流:
                        此抽象类是表示所有字节输入流的父类。

                        定义了所有子类共性的所有方法:

int read():
    从输入流中读取数据的下一个字节。

int read(byte[] b):
    从输入流中读取一定数量的字节,将其存入缓冲区数组b中

void close():
    关闭此输出流并释放与该流关联的所有系统资源


                    java.io.FileInputStream extends InputStream
                        FileInputStream:
                            文件字节输入流
                        作用:
                            把硬盘文件中的数据,读取到内存使用中

                        构造方法:

FileInputStream(String name)
FileInputStream(File file)
    参数:读取文件的数据源
        String name :目的地是一个文件的路径
        File file:目的地是一个文件

                        构造方法的作用:
                            1.会创建一个FileInputStream对象
                            2.会把FileInputStream对象指定构造方法中要读取的文件。

                        字节输入流的使用步骤:
                            1.创建FileInputStream对象,构造方法中要绑定要读取的数据源
                            2.使用FileInputStream对象中的方法read,读取文件
                            3.释放资源


                        字节流一次读入多个字节的方法:
                            int read(byte[] b)从输入流中读取一定数量的字节,将其存入缓冲区数组b中
                            数组的长度一般定义为1024(1Kb)或者是1024的整数倍

                        String类的构造方法:

String(byte[] bytes):
    把字节数组转换成字符串

String(byte[] bytes,int offset, int length):
    把字节数组中的一部分转换为字符串,offset:开始索引,length:装换的字节个数

            读入的文件一定要存在,否则报异常FileNotFoundException
                读取字节原理:
                    一次读取一个字节:
                        首先在硬盘中存有a.txt。在程序开始运行时,创建一个FileInputStream对象指针指向a.txt文件中的第一个字符内容,然后fis.read()方法调用OS,OS利用自己的方法来读取数据,数据通过OS->JVM->fis.read()读出来一个字读完,指针移向下一个字节,当指针移动到结束标记时,在fis.read()中读出的就是-1

                    一次读取多个字节:
                        首先在硬盘中存有a.txt。在程序开始运行时,创建一个FileInputStream对象指针指向a.txt文件中的第一个字符内容,然后fis.read()方法调用OS,OS利用自己的方法来读取数据,数据通过OS->JVM->fis.read()读出来一个字读完,发现数组中还有空位于是读取下一字节,当当指针移动到结束标记时,停止读取
                


            输出操作:
                从内存中写出以字符/字节为单位的数据到硬盘的指定文件中

            写入数据的原理(内存-->硬盘)
                java程序-->JVM-->OS-->OS写数据的方法-->把数据写到文件中

            FileWriter/FileOutputStream:
                java.io.Writer:字符输出流,是所有字符输出流最顶层的父类,是一个抽象类                                            共性的成员方法:

- void write(int c):
    写入单个字符
    FileWriter(字符流状态)从内存中将数据以字符的形式写到硬盘的指定文件中,文件如果不存在则自动创建文件
    FileOutputStream(字节流状态)从内存中将数据以字节的形式写到硬盘的指定文件中,文件如果不存在则自动创建文件



- void write(char/byte[] b/cbuf):
    写入字符数组.
    一次写多个字节的情况:
         若写的第一个字节是正数(0-127),则显示时会查询ASCII表
         若第一个字节是负数,那么第一个字节会和第二个字节一起组成一个中文显示,查询系统默认码表(GBK)
         byte[] getBytes() 把字符串转换为字节数组


- void write(字符串.toCharArray())方法:
    仅针对FileWriter(字符流状态)从内存中将数据以字符串的形式写到硬盘的指定文件中,
    文件如果不存在则自动创建文件


- void write(String str):
    写入字符串
    写入字符的方法:可以使用string类中的方法把字符串转换为字节数组
                                
                            
- abstract void write(char cbuf,int offset,int len):
    写入字符数组某一部分,offset数组开始索引,len写的字符个数


- void write(String str,int off,int len):
    常见- void write(c/bbuf,0,len);
    写入字符串某一部分,offset数组开始索引,len写的字符个数
    FileWriter(字符流状态)从内存中将数据以字符数组的形式写到硬盘的指定文件中,文件如果不存在则自动创建文件
    FileOutputStream(字节流状态)从内存中将数据以字节数组的形式写到硬盘的指定文件中,文件如果不存在则自动创建文件


- void flush():
    刷新该流的缓冲


- void close():
    关闭此流先要刷新它,关闭此节点流,在关闭前先判断关闭的流是否为空。


flush方法和close方法的区别
    - flush:刷新缓冲区,流对象可以继续使用
    - close:先刷新缓冲区,然后通知系统释放资源,流对象不能再使用了

                java.io.FileWriter extends OutputStreamWriter extends Writer
                    FileWriter:
                        文件字符输出流
                    作用:
                        把内存中字符数据写入文件中

                    构造方法:

FileWriter(File file)由给定的File对象构造一个FileWriter对象
FileWriter(String fileName)根据给定的文件名构造一个FileWriter对象
    参数:写入数据的目的地
        String fileName:文件的路径
        File file:是个文件

                    构造方法的作用:
                        1.会创建一个FileWriter对象
                        2.会根据构造方法中传递的文件/文件路径,创建文件
                        3.会把FileWriter对象指向创建好的文件

                    字符输出流的使用步骤
                        1.创建FileWrite对象,构造方法中要绑定写入数据的目的地
                        2.使用FileWrite中write方法,把数据写到内存缓冲区中(字符转换到字节的过程)
                        3.使用FileWrite中flush方法,把内存缓冲区中的数据,刷新到文件中
                        4.释放资源(先把内存缓冲区中的资源刷新到文件中)

                

                    续写和换行
                        写出的文件可以不存在,若不存在则直接自动创建此文件;若文件存在则{
                            new FileWriter(new File,false)/new FileWriter(new File):对原有文件进行覆盖
                            new FileWriter(new File,true):对原有文件进行追加
                        }

                        续写,追加写:使用两个参数的构造方法

FileWrite(String fileName,boolean append)
FileWriter(File file,boolean append)
    参数:
        String fileName, File file:写入数据的目的地
        boolean append:
            续写开关,true不会创建新的文件覆盖源文件;
                     false创建新的文件覆盖源文件

                        换行:
                            Windows:\r\n
                            linux:/n
                            mac:/r

                java.io.OutputStream:字节输出流
                    此抽象类是表示输出字节流的所有类的超类
                    定义了一些子类共性的成员方法:

-public void close();
    关闭此输出流并释放与此流相关的任何系统资源

-public void flush();
    刷新此输出流并强制任何缓冲的输出字节被写出

-public void write(byte[] b);
    将b.length字节从指定的字节数组写入此输出流

-public void write(byte[] b,int off,int len);
    指定的字节数组写入len字节,从偏移量off开始输出到此输出流

-public abstract void write(int b);
    将指定的字节输出流。

                java.io.FileOutputStream extends OutputStream
                    FileOutputStream:
                        文件字节输出流

                    作用:
                        把内存中的数据写入到硬盘的文件中。

                    FileOutputStream流底层实现:
                        首先创建一个FileOutputStream对象,然后根据写入的路径在相应硬盘创建一个文件,之后流对象指向创建好的流对象。在写数据是会将十进制数据转换成二进制数据,硬盘中存储的数据都是字节(字节是硬盘中存储的最小单位)1字节等于8位。任意文本编辑器在打开时均会查询编码表,把字节转换到字符表示:0-127查询ASCII表,其他数值查询系统默认码表

                    构造方法:

FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(File file):创建一个向指定 File 对象表示的文件中写入数据的文件输出流
    参数:写入数据的目的
        String name :目的地是一个文件的路径
        File file:目的地是一个文件

                    构造方法的作用:
                        1.创建一个FileOutputStream对象
                        2.会根据构造方法中传递的文件/文件路径,创建一个空的文件
                        3.会被FileOutputStream对象指向创建好的文件

        
                    字节输出流的使用:
                        1.创建fileOutPutStream对象,构造方法中传递写入数据的目的地
                        2.使用fileOutPutStream对象中的方法write,把数据写入到文件中
                        3.释放资源(流使用会占用一定内存,使用完毕要把内存清空,提高程序的效率)

                    追加写/续写:使用两个参数的构造方法

FileOutputStream(String name,boolean append)
    创建一个想具有指定name的文件中写入数据的输出文件流
FileOutputStream(File file,boolean append)
    创建一个想指定file对象表示的文件中写入输出的文件输出流

    参数:
        String name,File file:写入数据的目的地;
        boolean append:追加写开关;
            true:创建对象不会覆盖源文件,继续在文件末尾追加写数据
            false:创建一个新文件覆盖源文件

                写换行:写换行符号。
                        Windows:\r\n
                        linux: /n
                        mac: /r
        tip:
            tip1.针对文本文件(.txt,.java,.c,.cpp)应该采用字符流进行操作,如果采用字节流进行操作容易出现乱码,若采用字节流,则应该避免在控制台输出
            tip2.针对非文本文件(.doc,.jpg,.mp3,.mp4,.avi,.ppt。。。)应该采用字节流进行操作
            tip3.NIO支持面向缓冲区的(IO是面向流的)、基于通道的IO操作,NIO将以更加高校的方式进行文件的读写操作
            tip4.知道循环次数用for不知道循环此时用while
            tip5.使用字节流读取中文文件
                1个中文:
                    GBK:占用两个字节
                    UTF-8:占用3个字节


    五、处理流的使用:    
        1.处理流之一:缓冲流的使用
            1.缓冲流基本知识:
                 缓冲流就是对基本流{字节输入,输出流;字符输入,输出流}的加强。
                    传统的基本流中:读写文件均以字符为单位,效率低下。
                    缓冲流中:读写文件均以字符数组为单位,改进了传统基本流的效率低下问题。
                java读写数据的过程:java程序中有相应的输入输出流,这些流调用JVM,然后JVM调用OS,OS完成相应操作

            2.缓冲流:
                BufferedInputStream,BufferedOutputStream{二者不用处理文本文件}
                BufferedReader,BufferedWriter{二者不用于处理非文本文件}

                java.io.BufferedInputStream extends InputStream
                    BufferedInputStream:字节缓冲输入流
                    继承自父类的共性成员方法:

int read():
    从输入流中读取数据的下一个字节

int read(byte[] b):
    从输入流中读取一定数量的字节,将其存储在缓冲区数组b中

void close():
    关闭此输入流并释放与此年流有关的所有资源

                    构造方法:

BufferedInputStream(InputStream in)
    创建一个新的BufferedInputStream并保存其参数,即输入流in,以便将来使用
BufferedInputStream(InputStream in,int size)
    创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用

    参数:
        InputStream in:
            字节输入流,可以传递FileInputStream,
            缓冲流会给FileInputStream增加一个缓冲区,
            通过FileInputStream的读取效率
        int size:
            指定缓冲流内部缓冲区的大小,不指定默认

                    使用步骤:
                        1.创建FileInputStream对象,构造方法中绑定读取的数据源
                        2.创建BufferedFileInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
                        3.是用BufferedFileInputStream对象中的read方法,读取文件
                        4.释放资源


                java.io.BufferedOutputStream extends OutputStream
                    BufferedOutputStream:字节缓冲输出流
                    继承自父类的共性成员方法:

- public void close():
    关闭此输出流并释放与此输出流有关的所有资源

- public void flush():
    刷新此输出流并强制任何缓冲的输出字节被写出

- public void write(byte[] b):
    将b.long字节从指定的字节数组写入此输出流

- public void write(byte[] b,int off.int long):
    从指定的字节数组写入len字节,从偏移量off开始半输出到此输出流

- public abstract void write(int b):
    将指定的字节输出流

                    构造方法:

BufferedOutputStream(OutputStream out)
    创建一个新的缓冲输出流将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out,int size)
    创建一个新的缓冲输出流,将具有指定缓冲区大小的数据写入底层输出流。

    参数:
        OutputStream out:
            字节输出流:可以传递FileOutputStream,
            缓冲流会给FileOutputStream增加一个缓冲区,
            提高FileOutputStream写入效率
        int size:
            指定缓冲流内部缓冲区的大小,不指定默认

                    使用步骤:
                        1.创建FileOutputStream对象,构造方法中要绑定输出目的地
                        2.创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象,提高FileOutputStream对象使用效率
                        3.使用BufferedOutputStream对象的write方法,把数据写到内部缓冲区
                        4.使用BufferedOutputStream对象的flush方法,把缓冲区中的数据刷新到文件中
                        5.释放资源(先调用flush方法刷新数据,使得第4不可以省略)


                java.io.BufferedReader extends Reader

                    继承父类共性成员方法:

 int read():
    读取单个字符并返回

int read(char[] cbuf):
    一次读取多个字符,间字符读入数组

void close():
    关闭该流并释放与值相关的所有资源

                    构造方法:

BufferedReader(Read in)
    创建一个使用默认大小缓冲区的缓冲字符输入流
BufferedReader(Read in,int sz)
    创建一个指定大小输入缓冲区的缓冲字符输入流

    参数:
        Reader in:
            字符输入流,传递FileReader,
            缓冲流会给FileReader增加一个缓冲区,
            提高FileReader的读取效率
        int sz:
            指定了缓冲区大小

                    特有成员方法

String readLean():
    读取一个文本行,读取一行数据。
    行的终止符号:
        通过下列终止符号可认为某行已经终止:
            换行('\n')、回车('\r')或者回车后直接跟着换行(\r\n)
    返回值:
        包含该行的字符串,不包含任何终止符,若到达流末尾,则返回NULL

                    使用步骤:
                        1.创建字符缓冲流对象,构造方法中传递字符输入流
                        2.使用字符缓冲输入流对象中的方法read/readLine读取文本
                        3.释放资源


                java.io.BufferedWriter extends Writer
                    BufferedWriter:字符缓冲输出流

                    继承自父类的共性成员方法:

- void write(int c):
    写入单个字符

- void write(char[] cbuf):
    写入字符数组

- abstract void write(char cbuf,int offset,int len)
    写入字符数组某一部分,offset数组开始索引,len写的字符个数

- void write(String str)
    写入字符串

- void write(String str,int off,int len):
    写入字符串某一部分,offset数组开始索引,len写的字符个数

- void flush()
    刷新该流的缓冲

- void close()
    关闭此流先要刷新它

                    构造方法:

BufferedWriter(Writer out):
    创建一个使用默认大小输出缓冲区的缓冲字符输出流
BufferedWriter(Writer out,int sz):
    创建一个使用给定大小输出缓冲区的新缓冲字符输出流

    参数:
        Writer out:
            字符输出流,可以传递FileWriter,
            缓冲流会给FileWriter增加一个缓冲区,提高FileWriter的写入效率
        int sz:
            指定缓冲区大小,不写默认大小

                    特有成员方法:

void newline()写入一个行分割符,会根据不同的操作系统。获取不同的行分隔符{
    换行:
        windows:\r\n
        linux:/n
        mac:/r
}

                    使用步骤:
                        1.创建字符缓冲输出流对象,构造方法中传递字符输出流
                        2.调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
                        3.调用字符缓冲输出流中方法flush,把内存缓冲区中的数据刷新到文件中
                        4.释放资源

            3.作用:
                提高流的读取/缓冲的速度{原因:内部提供了一个容量为8192字节大小缓冲区,即8kb}
            4.方法:
                flush()方法:刷新缓冲区,一般是内置调用,不需要开发者显示调用此函数
                newLine()方法:提供换行操作
            5.使用步骤:
                1、File类的实例化
                2、流的实例化:
                    先实例化节点流,然后再实例化处理流,将节点流作为处理流的参数
                3、读入/写出的操作,造相应的字符/字节数组,对处理流进行操作即可
                4、资源的关闭:
                    先关闭外层处理流,再关闭内层节点流;在关闭外层流的同时,内层流也会自动的进行关闭,因此关于内层流的关闭操作可以省略
                5、异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try...catch...finally结构处理
            6.处理流:
                “套接”在已有流的基础之上

        2.处理流之二:转换流的使用:(使用步骤同流的使用步骤)

            1.转换流(属于字符流):
                InputStreamReader:字节输入流转换为字符输入流
                    new InputStreamReader(new FileInputStream())使用系统默认字符集
                    new InputStreamReader(new FileInputStream(),charsetName)指明了字符集,由读入文件保存时的字符集决定
                OutputStreamWriter:字符的输出流转换为字节的输出流

                java.io.InputStreamReader extends Reader
                    InputStreamReader是字节流通向字符的桥梁,,可以使用的指定的charset将要写入流中的字符编码成字节。(编码:把能看懂的变成看不懂的)

                    继承自父类共性成员方法:

int read():
    从输入流中读取数据的下一个字节

int read(byte[] b):
    从输入流中读取一定数量的字节,将其存储在缓冲区数组b中

void close():
    关闭此输入流并释放与此年流有关的所有资源

                    构造方法:

InputStreamReader(InputStream in):
    创建一个默认字符集的InputStreamReader
InputStreamReader(InputStream in,String charset)
    创建指定字符集的InputStreamReader

    参数:
        InputStream in:
            字节输入流,用于读取文件中保存的字节
        String charName:
            指定的编码表名称,不区分大小写,
            可以是utf-8/UTF-8,gbk/GBK等不指定默认使用utf-8

                    使用步骤;
                        1.创建InputStreamReader对象,构造方法中传递字节输入流和指定的编码表名称
                        2.使用InputStreamReader对象中的方法read读取文件
                        3.释放资源

                    注意事项:
                        构造方法中指定的编码表名称要和文件的编码相同,否则产生乱码

                java.io.OutputStreamWriter extends writer
                    OutputStreamWriter:是字符通向字节流的桥梁,可以使用的指定的charset将要写入流中的字符编码成字节。(编码:把能看懂的变成看不懂的)

                    继承自父类共性成员方法:

- void write(int c):
    写入单个字符

- void write(char[] cbuf):
    写入字符数组

- abstract void write(char cbuf,int offset,int len)
    写入字符数组某一部分,offset数组开始索引,len写的字符个数

- void write(String str)
    写入字符串

- void write(String str,int off,int len)
    写入字符串某一部分,offset数组开始索引,len写的字符个数

- void flush()
    刷新该流的缓冲

- void close()
    关闭此流先要刷新它

                    构造方法:

OutputStreamWriter(OutputStream out):
    创建使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out,String charName)
    创建使用指定字符集的OutputStreamWriter

    参数:
         OutputStream out:
            字节输出流,可以用来写转换之后的字节到文件中
         String charName:
            指定的编码表名称,不区分大小写,
            可以是utf-8/UTF-8,gbk/GBK等不指定默认使用utf-8

                        使用步骤:
                            1.创建OutputStreamWriter对象,构造方法中传递字节输出流和指定的编码表名称
                            2.使用OutputStreamWriter对象中的方法write,把字符转换为字节存储到缓冲区中(编码)
                            3.使用OutputStreamWriter对象中的方法flush,把内存缓冲区中的字节刷新到文件中(使用字节流写字节的过程)
                            4.释放资源

            2.提供字符流与字节流之间的转换

            3.编码与解码:
                解码(InputStreamReader):
                    字节、字节数组 --->字符数组、字符串
                    字节(看不懂的)-->字符(能看懂的)

                编码(按照某种规则将字符存储到计算机中)(OutputStreamWriter):
                    字符数组、字符串 --->字节、字节数组
                    字符(能看懂的)-->字节(看不懂的)

                字符编码:一套自然语言与二进制数之间的对应规则

            4.字符集(由字符编码构成的表):
                计算机的底层存储是以二进制存储,为了方便人们使用,让计算机可以识别字符串,于是将数字用于表示字符串,并且一一对应,
                于是就形成了一张表,此表就是编码表。常见编码表:

ASCII:
    美国标准信息交换码,用一个字节的7位可以表示一个字符,
    拓展使用8位表示一个字符,共256个字符,常用128个字符

ISO-8859-1:
    拉丁码表,欧洲码表,用一个字节的8位可以表示。兼容ASCII码

GB2312:
    中国的中文编码表,最多用两个字节编码所有的字符。
    简体中文,兼容ASCII码,收录7000多个汉字

GBK:
    中国的中文编码表升级,融合了更多的中文文字符号。
    最两个字节编码;以GB2312为基础扩展到21003个汉字,
    也支持日韩汉字,使用两个字节存储一个中文{你好-->-55-44,-33-34}

GB19030:
    在GBK基础上扩展到70224个汉字,采用多字节编码,
    每个字可以采用1个、2个或4个字节组成,同时支持少数民族文字

在中文字符集中字节的区分:
    以首位为区分标志,当首位为0,则表示一个字节单独表示一个字符;
    当首位为1,则表示两个字节表示一个字符

Unicode:
    国际标准码。为每个字符分配唯一的字符码。
    所有的文字都用两个字节来表示,表示一个字符集。
    由于可能存在存储浪费,或是字符存储不明确等原因。
    在具体实现依靠UTF-8/-16/-32。即所有国家的编码,常用utf-8,4个字节

UTF-8:
    变长的编码方式,可用1-4个字节来表示一个字符;一个汉字由3个字节存储。
    国际标准码表,使用三个字节存储一个中文{你好-->-11-12-13,-19-56-78}

                注:
                    FileReader可以读取IDEA默认编码格式(UTG-8)的文件
                    FileReader读取系统默认编码(中文GBK)会产生乱码

            5.转换流原理
                一读:
                    传统:
                        硬盘中的文件数据通过字节输入流(FileInputStream)将不同字符集的字节数据交给FileReader,通过FileReader传给java程序FileReader仅查询idea默认的UTF-8表,把字节转换为字符(解码),由于所有字符集转换的格式只有idea默认格式UTF-8故可能产生乱码
                    使用转换流:
                        硬盘中的文件数据通过字节输入流(FileInputStream)将不同字符集的字节数据交给InputStreamReader,通过InputStreamReader传给java程序InputStreamReader(是字节流通向字符流的桥梁),可以查询指定的字符集(不限于UTF-8),把字节转换为字符(解码),所以不会产生乱码

                一写:
                    传统:
                        java程序中的数据通过FileWriter将字符转换为字节(只采用idea仅有的默认UTF-8字符集进行编码),通过FileOutputStream将数据写入硬盘相应文件
                    使用装换流:
                        java程序中的数据通过OutputStreamWriter将字符转换为字节(采用指定的字符集进行编码),通过FileOutputStream将数据写入硬盘相应文件

        3.处理流之三:对象流的使用:
            1.ObjectInputStream
                java.io.ObjectInputStream extends InputStream
                    ObjectInputStream:对象的反序列化流
                    作用:把文件中保存的对象,以流的方式读取出来

                构造方法:

 ObjectInputStream(InputStream in):
    创建指定InputStream读取的ObjectInputStream
    参数:
        InputStream in字节输入流

                特有的成员方法:

 Object readObject()从ObjectInputStream读取对象

                使用步骤:
                    1.创建ObjectInputStream对象,构造方法中传递字节输入流
                    2.使用ObjectInputStream对象的readObject方法读取保存对象的文件
                    3.释放资源
                    4.使用读取出来的对象(打印)

                readObject方法抛出了ClassNotFoundException(class文件找不到异常)
                当不存在对象的class文件时抛出异常
                反序列化前提:
                    1.类必须实现Serializable
                    2.必须存在类对应的class文件


            2.ObjectOutputStream
                java.io.ObjectOutputStream extends OutputStream
                    ObjectOutputStream:对象序列化流
                    作用:把对象一流的方式写入文件中保存

                    构造方法:

ObjectOutputStream(OutputStream out):
    创建写入指定OutputStream的ObjectOutputStream
    参数:
        OutputStream out:字节输出流

                   特有的成员方法:

void writeObject(Object obj)将指定的对象写入ObjectOutputStream

                    使用步骤:
                        1.创建ObjectOutputStream对象,构造方法中传递字节输出流
                        2.使用ObjectOutputStream对象的writeObject方法把对象写入文件中
                        3.释放资源

            3.作用:
                用于存储和读取基本类型数据或对象的处理流,它的强大之处可以把java中的对象写入到数据源中,也能把对象从数据源中还原回来

            4.要想一个java对象是可序列化的,需要满足相应的要求

            5.序列化与反序列化:
                序列化:
                    将对象从内存持久化保存到磁盘/硬盘中,或者通过网络传输出去
                    把对象以流的方式写入到文件中保存,叫写对象,也叫对象序列化;对象中不仅仅包含的是字符,使用字节流
                    ObjectOutputStream:对象的序列化流
                    对象序列化通过writeObject(对象)将对象从字符转变为字节
                反序列化:
                    将对象从硬盘调入到内存中
                    把文件中保存的对象,一流的方式读取出来,叫做读对象,也成对象的反序列化
                    读取的文件保存的都是字节,使用字节流
                    ObjectInputStream:对象的反序列化
                    对象的反序列化通过 Object obj=new 类(对象)将文件数据从字节转换为字符(对象)

                对象的序列化机制:
                    允许把内存中的java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地存储在磁盘上,或通过网络将这种二进制流传输到另外一个网络结点。当其他程序获取了这种二进制流,就可以回复成原来的java对象

            6.序列化与反序列化的注意事项:
                1、序列化和反序列化的时候,会抛出java.io.NotSerializableException没有序列化异常
                类通过实现java.io.Serializable接口或实现Externalizable接口以启用其序列化功能。未实现此功能的类将无法使用其任何状态序列化或反序列化
                Serializable接口也称标记接口(其内部并未定义任何抽象方法或属性):
                    要进行序列化和反序列化的类必须实现Serializable接口,就会给了增加一个标记
                    当进行序列化和反序列化时就会检测类上是否有此标记
                        有:就可以序列化和反序列化
                        无:抛出java.io.NotSerializableException异常

                需要当前类提供一个全局常量。自定义标识序列版本号:public static final long serialVersionUID = 自定义标识序列L;
                    使用理由:
                        serialVersionUID是用于表明类的不同版本间的兼容性,其目的是以序列化对象进行版本控制,有关个版本反序列化时是否兼容。若类没有显式定义serialVersionUID这个静态常量,它的值是java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID可能发生变化,那么在反序列化时可能出错。即java的序列化机制是通过在运行时判断了类的serialVersionUID来验证版本的一致性。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类进行比较如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常(InvalidCastException)

                除了当前类需要实现Serializable接口外,还必须保证其内部所有属性也必须是可序列化的(默认情况下,基本数据类型可序列化)

                补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量,因为一旦被这两个关键字修饰后,这个属性就不是一个对象私有,而是一个类共有

                2、static静态关键字:
                    静态优先于非静态加载到内存中(静态优先于对象加载到内存)
                    被static修饰的成员变量不能被序列化,序列化的都是对象

private static int age;
oos.writeObject(new Person("小明",23));
Object o = ois.readObject();
Person{name='小明', age=0}

                3、transient瞬态关键字:
                    被transient修饰的成员变量,不能被序列化

private transient int age;
oos.writeObject(new Person("小明",23));
Object o = ois.readObject();
Person{name='小明', age=0}


                4、java.io.InvalidClassException异常:
                    定义了一个person类实现了Serializable接口,并且实现了构造/get/set方法,编译器java.exe把person.java文件编译生成person.class文件person类实现了Serializable接口,就会根据类的定义给person.class文件添加一个序号serialVersionUID = -7970,生成的person.txt文本中也会存在一个serialVersionUID = -7970序列号。在进行反序列化的时候,会使用person.class文件中的序列号和person.txt文件中的序列号进行比较,如果序列号一直那么反序列化成功,反之则不成功,不成功则抛出java.io.InvalidClassException异常。由此可知:
                        每次修改类的定义,都会给class文件生成一个新的序列号;若要无论是否对类的定义进行修改都不重新生成新的序列号,那么可以手动给类天机一个序
                            列号:
                                格式在Serializable接口规定:
                                可序列化类可以通过声明为"serialVersionUID"的字段(该字段必须是静态static,是最终final的long型字段)显示声明其自己的serialVersionUID
                                static final long serialVersionUID =42L; 常量不能改变

        4.处理流之四:任意存储文件流的使用:
            1.RandomAccessFile直接继承于java.long.Object类,实现了DataInput和DataOutput接口
            2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流,用不同的实例化以示区分
            3.其构造器

public RandomAccessFile(File file,String mode);
public RandomAccessFile(String name,String mode);

                 其中mode确定了RandomAccessFile的访问模式:
                    r:只读方式打开;
                    rw:打开以便读取和书写
                    rwd:打开以便读取和书写;同步文件内容的更新
                    rws:打开以便读取和书写;同步文件内容和元数据的更新
            4.若RandomAccessFile作为一个输出流出时,写出到的的文件若不存在,则在执行过程中自动创建;若写出到的文件存在,则会对原有文件内容从首行开始进行覆盖.
            5.常用方法:

write():
    写或覆盖

long getFilePoint()
    获取文件记录指针的当前位置

void seek(long pos)
    将文件记录指针定位到pos位置

        5.Properties集合的使用:
            java.util.Properties集合 extends Hashtable implement Map
                Properties类表示了一个持久到额属性集,Properties可以保存在流中或从流中加载
                Properties集合是唯一一个和IO流相结合的集合
                    可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
                    可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用

            属性列表中每个键及其对应的值都是一个字符串
                Properties集合是一个双列集合,key和value默认都是字符串


    六、其它流的使用:
        1.标准输入/输出流:
            1.1基本概念:
                System.in:标准输入流,默认从键盘输入
                System.out:标准输出流,默认从控制台输出

            1.2使用:
                System类的serIn(InputStream is)/setOut(PrintStream ps)方式重新指定输入和输出的流


        2.打印流:
            PrintStream和PrintWriter
            提供了一系列重载的print()和println()

            java.io.PrintStream:打印流
                PrintStream:为其他输出流添加功能,使他们能够方便的打印各种数据值表示形式

            PrintStream特点:
                1.只负责数据你的输出,不负责数据的读取
                2.与其他输出流不同,PrintStream永远不会抛出IOException
                3.特有方法:print,println

void print(任意类型值)
void println(任意类型值并换行)

            构造方法:

PrintStream(File file):
    输出到目的地是一个文件

PrintStream(OutputStream out)
    输出到目的地是一个字节流

PrintStream(String fileName)
    输出到目的地是一个文件路径

            PrintStream extends OutputStream

            继承自父类的成员方法:

- public void close():
    关闭此输出流并释放与此输出流有关的所有资源

- public void flush():
    刷新此输出流并强制任何缓冲的输出字节被写出

- public void write(byte[] b):
    将b.long字节从指定的字节数组写入此输出流

- public void write(byte[] b,int off.int long):
    从指定的字节数组写入len字节,从偏移量off开始半输出到此输出流

- public abstract void write(int b):
    将指定的字节输出流

                注:
                    若使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表97->a
                    若使用自己特有的方法print/println写数据,写的数据原样输出:97->97

            可以改变输出语句的目的地(打印流的流向)
            输出语句默认在控制台输出
            使用System.setOut方法改变输出语句的目的地改为参数中传递的打印流的目的地
                static void setOut(PrintStream out)重新分配“标准”输出流


        3.数据流:
            DataInputStream和DataOutputStream
            作用:
                用于读取或写出基本数据类型的变量或字符串,具体实现可以将内存中的字符串、基本数据类型变量写出到文件中
            注:
                读取不同类型的数据的顺序要与当初保存数据的顺序一致
            flush()刷新操作:将内存中的数据写入文件

以上是本篇小节,不喜勿喷,感谢理解

相关链接:

【JAVASE(10)】JAVASE学习--文件(File)类与IO流篇(2)_lixxkv的博客-CSDN博客
【JAVASE(9)】JAVASE学习--泛型篇_lixxkv的博客-CSDN博客

你可能感兴趣的:(JAVASE学习,java,开发语言,后端)