【黑马程序员】异常,File类,IO流——Java复习笔记

原创 2015年11月20日 16:08:53

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

异常

(1)异常的体系
    Throwable
        |--Error    严重问题,我们不处理。
        |--Exception
            |--RuntimeException及其子类  运行期异常,我们需要修正代码
            |—除RuntimeException及其子类以外的所有异常类  编译期异常,必须处理的,否则程序编译不通过

(2)异常的处理:
    A:JVM的默认处理
        把异常的名称,原因,位置等信息输出在控制台,但是呢程序不能继续执行了。

    B:自己处理
        a:try...catch(异常名)…finally
            try里面的代码越少越好

            try里写可能出异常的代码,在catch里编写处理代码,出现异常后不再报错,而是执行catch里的内容,然后继续往下执行.  

            try里面有一条语句出现了异常,jvm会生成一个异常对象,然后把这个对象抛出,和catch里面的类去匹配并执行处理(若匹配不到对应的类则报错),不再执行try里接下来的语句

            如果不知道会出现什么异常 catch里异常名就写Exception (效率会低,但是不会有漏网之鱼.所以为了提高效率,能明确是什么异常就尽量明确)

            父类异常catch要在子类异常后面

        b:throws
            把自己处理不了的,在方法上声明,告诉调用者,这里有问题

    C:JDK7新特性
        try{…}catch(异常名1 | 异常名2 | ..e){…} 
        这几个异常都用同一个处理方式
        这几个异常必须是同级关系,不能是继承关系

    D:异常中要了解的一些方法
        String getMessage() 返回异常的消息字符串

        String toString() 返回此异常的简单信息描述,由此对象的全路径类名+”: ”+e.getLocalizedMessage()得到        getLocalizedMessage方法如果未被重写,则默认返回getMessage方法的结果

        void printStackTrace() 输出toString() + 异常出现的位置

        void printStackTrace(PrintStream s) 通常用此方法将内容保存在日志文件中以便查阅

    E:throws抛给调用者处理
        有些时候没有权限去处理某个异常,或者处理不了,为了解决问题,就采用抛出的方法

        格式:  throws 异常类名1,异常类名2,.....
        此格式必须跟在方法的()后面

        若抛出的时运行期异常,调用者不处理,运行时就会报错并停止运行;若是编译期异常 则必须catch该异常 否则编译不了

    F:throw把异常对象抛出
int a=10;int b=0;
if(b == 0){
    throw new ArithmeticException(“b不能为0”);
}else{
    System.out.println(a/b);
}   //“ ”的内容会被getLocalizedMessage获取
        jvm运行到这里会调用该异常的printStackTrace方法.然后停止,不再往下执行

    捕获异常的小技巧:哪个方法报的错就查看其源码,看它throws的什么异常.

(3)面试题
    A:编译期异常和运行期异常的区别?
        编译期异常 必须要处理的,否则编译不通过
        运行期异常 可以不处理,也可以处理

    B:throw和throws是的区别
        throw:
            在方法体中,后面跟的是异常对象名,并且只能是一个.用于手动抛出指定异常,是主动的.而jvm报错是被动的

            throw抛出的是一个异常对象,说明这里肯定有一个异常产生了,程序执行到throw就停止,不再继续执行.如果想捕获该异常就要在方法声明里throws,然后调用者try..catch该异常  

            相比jvm的报错,throw还可以通过构造方法 传入并抛出异常的详细信息

        throws:
            在方法声明上,后面跟的是异常的类名,可以是多个

            throws是声明方法有异常,是一种可能性,这个异常并不一定会产生

(4)finally关键字及其面试题
    A:finally用于释放资源,不管正常异常,它的代码永远会执行。
        特殊情况:在执行到finally之前jvm退出了(比如执行finally前遇见了System.exit(0);)

    B:面试题
        a:final,finally,finalize()的区别?
            final是最终的意思,修饰 类/成员变量/成员方法
            finalize()是Object的方法,用于垃圾回收

        b:如果在catch里面有return,请问finally还执行吗?如果执行,在return前还是后
            答:会,前。准确的说是在中间
int a=10;
try{ 
    System.out.println(a/0);
}catch(ArithmeticException e){
    a=30;
    return a;   //程序执行到这一步的时候,这里是return 30;而不是return a; 这个返回路径就形成了,然后执行finally,a变成40,然后回到返回路径,还是return 30;
} finally{  
    a=40; 
}
return a;
//输出结果是30
    C:异常处理的变形
        try...finally 这种做法目的是为了释放资源

(5)自定义异常
    继承自Exception或者RuntimeException,只需要提供无参构造和一个带参构造(可直接super调用父类)即可.    也可以什么都不写

(6)异常的注意事项
    A:父的方法有异常抛出,子的重写方法在抛出异常的时候必须要抛出相同的异常或者父类异常的子类

    B:父的方法没有异常抛出,子的重写方法不能有异常抛出,只能在内部try catch处理

    C:父的方法抛出多个异常,子的重写方法抛出的异常不能是父类没有的,必须是相同的异常或者其子类

File

(1)IO流操作中大部分都是对文件的操作,所以Java就提供了File类供我们来操作文件. File是文件和目录路径名的抽象表示形式

(2)构造方法 (效果都一样,让File对象指向该文件/目录)
    注意   Mac是单/  
        windows是双\\

        mkdir方法要想在某个目录下创建内容,该目录必须存在
        mkdirs可以一次创建多级目录
        以上两个方法都只能创建文件夹

    A:File file = new File("e:\\demo\\a.txt"); 根据路径得到对象
        把a.txt封装成一个File对象(File对象指向这个文件)

    B:File file = new File("e:\\demo","a.txt"); 父目录和子文件/目录

    C:File file = new File("e:\\demo"); 
      File file2 = new File(file,"a.txt”);父File对象,子文件

(3)File类的功能
    A:创建功能
        创建时若没写盘符路径则默认在该Projects下
        boolean createNewFile() 创建文件
        boolean mkdir()  创建文件夹 如果存在则不创建,返回false 
        boolean mkdirs() 创建文件夹,如果目录不存在 会帮你创建

    B:删除功能
        boolean delete()  删目录的话,要求该目录为空

    C:重命名功能
        boolean renameTo(File dest)  如果路径一样则改名,不同则改名并剪切   
        File file = new File(“/mo/1.txt”);
        File file2 = new File(“/mo/dir/2.txt”);
        file.renameTo(file2)
        结果为:把1.txt文件改名为2.txt然后剪切粘贴到dir下覆盖原文件

    D:判断功能 返回值都是boolean
        isDirectory() 判断是否为目录
        isFile() 判断是否为文件
        exists() 判断是否存在
        canRead() 判断是否可读
        canWrite() 判断是否可写
        isHidden() 判断是否隐藏

    E:获取功能
        String getAbsolutePath() 获取绝对路径
        String getPath() 获取相对路径
        String getName() 获取名称
        long length() 获取长度,即文件大小:字节数
        long lastModified() 获取最后一次的修改时间 返回的毫秒值

    F:高级获取功能
        String[] list() 获取指定目录下的所有文件/文件夹的名称数组
        File[] listFile() 获取指定目录下的所有文件/文件夹的File数组

    G:过滤器功能  
        需实现FilenameFilter接口,并重写accept方法.方法体内通过判断语句得到并返回true则添加到list
        String[] list(FilenameFilter filter)
        File[] listFiles(FilenameFilter filter)

递归

(1)方法定义中调用方法本身的现象

(2)递归的注意事项;
    A:要有出口,否则就是死递归
    B:次数不能过多,否则内存溢出
    C:构造方法不能递归使用

(3)递归求阶乘
    /**
     * 递归求阶乘
     */
    public static int jieCheng(int n ){
        if (n == 1){
            return 1;
        }else {
            return n*jieCheng(n-1);
        }
    }
(4)练习:一对兔子,出生后第三个月起,每个月生一对兔子,生出来的兔子同理,求第20个月数兔子对数
    /**
     * 一对兔子,出生后第三个月起,每个月生一对兔子,生出来的兔子同理,求第20个月数兔子对数
     * 找规律
     * 第一个月 1对  第二个月 1对 第三个月 2对 第四个月 3对 第五个月 5对 第六个月 8对
     * 1 1 2 3 5 8
     * 方法1:数组
     * 方法2:变量的变化实现
     *      第1,2个月  1 , 1
     *      第2,3个月  1 , 2
     *      第3,4个月  2 , 3
     *      ....      a , b
     *      ..        b , a+b
     * 方法3:递归
     *
     */
    public static int rabbit(int m){
        int[] arr = new int[m];
        arr[0] =1;
        arr[1] =1;
        for (int x=2;x<m;x++){
            arr[x] =arr[x-1]+arr[x-2];
        }
        return arr[m-1];
    }
    public static int rabbit2(int m){
        int a = 1;
        int b =1;
        for (int x = 0;x<m-2;x++){
            int temp = a;
            a = b;
            b = b + temp;
        }
        return b;
    }
    public static int rabbit3(int m){
        if (m == 1 || m == 2){
            return 1;
        }else {
            return rabbit3(m-1)+rabbit3(m-2);
        }
    }

IO流

(1)IO用于在设备间进行数据传输的操作    

(2)分类:
    A:流向
        输入流 读取数据
        输出流 写出数据  写的时候文件不存在会自动创建

    B:数据类型
        字节流 
                字节输入流 InputStream
                字节输出流 OutputStream
        字符流
                字符输入流 Reader
                字符输出流 Writer

    注意:
        a:如果我们没有明确说明按照什么分,默认按照数据类型分。
        b:除非文件用windows自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流。  一般都用字节流

(3)FileOutputStream写出数据
    FileOutputStream()构造方法需要传入File对象或String路径名
    这个文件可以不存在,系统调用方法时会自动创建

    write方法参数列表有三种:
        (int b) 写一个字节
        (byte[] b) 写一个字节数组
        (byte[] b, int off, int len) 写一个字节数组的索引从off开始到len,包括off和len 

    A:操作步骤
        a:创建字节输出流对象
        b:调用write()方法 String.getBytes()把字符串转为byte数据写进去
        c:释放资源

    B:要注意的问题?
        a:创建字节输出流对象做了几件事情? 
            1创建文件 2创建对象 3把对象指向该文件

        b:为什么要close()?
            1让流对象变成垃圾,可以被回收 2通知系统去释放跟该文件相关的资源

        c:如何实现数据的换行? 
            .write(“\n”.getBytes())  

        d:如何实现数据的追加写入? 
            FileOutputStream(String name,boolean append) 用这个构造方法创建对象,向name的文件中写入数据,append如果为true则将字节写入文件末尾处(即追加写入)

(4)FileInputStream读取数据
    A:操作步骤
        a:创建字节输入流对象
        b:调用read()方法 
            int read() 读取一个字节
            int read(byte[] b) 读取一个字节数组
            返回读入缓冲区的字节总数
            通过测试,读取到的是-1说明已经读到末尾
        c:释放资源

    B:代码体现:一次读取一个字节
        FileInputStream fis = new FileInputStream("fos.txt");
        int by = 0;
        while((by=fis.read())!=-1) {
            System.out.print((char)by);
        }

(5)案例:
    A:复制文本文件
        封装数据源 FileInputStream in = new …
        封装目的地 FileOutputStream out = new …
        读写数据
        int b = 0;
        while((b = in.read()) != -1){
            out.write(b)
        }
        释放资源 out.close();  in.close();
        //此流程可以复制中文文本是因为读一个字节写一个字节,不做任何转换,而以前是读一个字节就转换为字符然后输出.
        在计算机中,中文的存储分2个字节,第一个字节肯定是负数,第二个正负都行

    B:一次读取一个字节数组 (效率远高于一次读取一个字节)
byte[] arr = new byte[1024];
int length ;
while((length = in.read(arr)) !=-1){
    System.out.print(new String(arr,0,length));
}
        如果不把长度限定为(0,length).会导致最后如果只剩下不到1024个字节的数据,读取的时候就只覆盖了数组里的前几个,后面几个没新的去覆盖,会输出旧的数据.数组长度一般定位1024,即一次读一1kb的数据. 效率远高于一次读取一个字节

        Java设计的时候考虑了这个,为了高效的读写,于是提供了字节缓冲区流(缓冲区类)

(6)字节缓冲区流
    构造方法需要传入IO流对象,因为该类只提供缓冲区,真正的操作还是靠IO流
    构造方法可以指定缓冲区小大,一般默认就行
    A:BufferedOutputStream 
    B:BufferedInputStream

(7)字符流

IO流分类
    字节流:reads /writes as byte
        InputStream
            FileInputStream
            BufferedInputStream //高效
        OutputStream
            FileOutputStream
            BufferedOutputStream //高效
    字符流:reads/writes as char , only use to text
        Reader
            FileReader
            BufferedReader //高效
        Writer
            FileWriter
            BufferedWriter //高效

字符流

(1)字节流操作中文数据不是特别的方便,所以就出现了转换流。
   转换流的作用就是把字节流转换字符流来使用。

(2)转换流其实是一个字符流
    字符流 = 字节流 + 编码表

(3)编码表
    A:就是由字符和对应的数值组成的一张表

    B:常见的编码表
        ASCII      ‘a’=97 ‘A’=65 ‘0’=48
        ISO-8859-1  拉丁码表  8位表示一个数据
        GB2312 简体中文
        GBK 是GB2312升级版
        GB18030 是GBK的升级版
        UTF-8 最多用三个字节来表示一个字符
        Unicode 国际标准码 融合多种文字,所有文字都用2个字节表示

    C:字符串中的编码问题
        编码  String -- byte[]
            byte[] getBytes(String charsetName) 把文字编译为字节数组

        解码  byte[] -- String
            String(byte[],String charsetName)通过指定字符集解码字节数组

(4)IO流中的编码问题
    转换流
    A:OutputStreamWriter
        OutputStreamWriter(OutputStream os):默认编码,GBK
        OutputStreamWriter(OutputStream os,String charsetName):指定编码。

    B:InputStreamReader
        InputStreamReader(InputStream is):默认编码,GBK
        InputStreamReader(InputStream is,String charsetName):指定编码

    C:编码和解码只要用的同一个编码表即可正常显示

(5)字符流
    Reader
        |—InputStreamReader 转换流
            |--FileReader
        |--BufferedReader
    Writer
        |--OutputStreamWriter
            |--FileWriter
        |--BufferedWriter

IO流小结

IO流
    |--字节流
        |--字节输入流
            InputStream 读取二进制数据
                int read():一次读取一个字节,并返回此字节
                int read(byte[] bys):一次读取一个字节数组,返回读入缓冲区的总字节数

                |--FileInputStream
                |--BufferedInputStream

        |--字节输出流
            OutputStream
                void write(int by):一次写一个字节
                void write(byte[] bys,int index,int len):一次写一个字节数组的一部分

                |--FileOutputStream
                |--BufferedOutputStream

    |--字符流
        |--字符输入流
            Reader 读取文本数据
                int read():一次读取一个字符,并返回此字节
                int read(char[] chs):一次读取一个字符数组,返回读入缓冲区的总字节数
                |--InputStreamReader
                    |--FileReader
                |--BufferedReader
                    |—LineNumberReader
                String readLine():一次读取一行数据,不包括换行符,如果到达某尾,返回null 效率低于一次读一个数组
                LineNumberReader特有方法:
                    int getLineNumber() 获得当前行号
                    void setLineNumber(int)设置行号

        |--字符输出流
            Writer
                void write(int ch):一次写一个字符
                void write(char[] chs,int index,int len):一次写一个字符数组的一部分

                |--OutputStreamWriter
                    |--FileWriter
                |--BufferedWriter
                    void newLine():写一个换行符
                    void write(String line):一次写一个字符串

数据操作流(操作基本类型数据的流)

(1)可以操作基本类型的数据

(2)流对象名称    
    DataInputStream
    DataOutputStream

内存操作流

(1)有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。

(2)三种
    A:ByteArrayInputStream,ByteArrayOutputStream
    B:CharArrayReader,CharArrayWriter
    C:StringReader,StringWriter

打印流

(1)字节打印流printStream,字符打印流printWriter
    printStream构造方法可以传入字节流/指定File/字符集/路径名
    printWriter造方法可以传入字节流/字符流/指定File/字符集/路径名

(2)特点:
    A:只操作目的地,不操作数据源(只写不读)
    B:可以操作任意类型的数据
    C:如果启用了自动刷新,在调用println/printf/format方法的时候,能够换行并刷新(即flush方法) 此时println等价于write+newLine+flush

    D:可以直接操作文件
        问题:哪些流可以直接操作文件呢?
            File开头的字节流/字符流,四个
            printStream,printWriter 两个
            剩下的看API,如果其构造方法能够同时接收File和String类型的参数,一般都是可以直接操作文件的

(3)复制文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
PrintWriter pw = new PrintWriter(new FileWriter("b.txt"),true);     
String line = null;
while((line=br.readLine())!=null) {
    pw.println(line);
}       
pw.close();
br.close(); 

标准输入输出流

(1)System类下面有这样的两个字段
    in 标准输入流
    out 标准输出流

(2)三种键盘录入方式
    A:main方法的args接收参数

    B:System.in通过BufferedReader进行包装
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = br.readLine();
        再通过Integer.parseInt(line)等方法把数据转为需要的类型

    C:Scanner
        Scanner sc = new Scanner(System.in);

(3)输出语句的原理和如何使用字符流输出数据
    A:原理
        System.out.println("helloworld");
        以上输出语句的原理如下
        PrintStream ps = System.out;
        ps.println("helloworld");

    B:涉及到字符数据的时候,把System.out用字符缓冲流包装一下使用
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

随机访问流RandomAccessFile

(1)可以按照文件指针的位置写数据和读数据。
(2)案例:
    A:写数据
    B:读数据
    C:获取和改变文件指针的位置
读:
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
int a = raf.readInt();
System.out.println("指针位置为:"+raf.getFilePointer());
char b = raf.readChar();
System.out.println("指针位置为:"+raf.getFilePointer());
String c = raf.readUTF();
System.out.println("指针位置为:"+raf.getFilePointer());
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println("指针位置为:"+raf.getFilePointer()); //20  int占了4个 char占了2个 四个汉字占了14个(UTF 3个字节  四个字就是12个 再加该方法内部再往后读2字节
//指定指针位置
raf.seek(4);
char ch = raf.readChar();
System.out.println(ch);
写:
raf.writeInt(100);
raf.writeChar('a');
raf.writeUTF("肯德基啊");
raf.close();

合并流SequenceInputStream

(1)把多个输入流的数据写到一个输出流中。只有读取

(2)构造方法:
    A:SequenceInputStream(InputStream s1, InputStream s2) 
    B:SequenceInputStream(Enumeration<? extends InputStream> e)
    具体使用方法同其他流 

序列化流

(1)ObjectOutputStream将对象按流一样的方式储存或传输 接收到后用ObjectInputStream读取就可还原

(2)如何实现序列化呢?
    让被序列化的对象所属类实现序列化接口并生成序列号ID值。Serializable
    该接口是一个标记接口。没有功能需要实现。 生成ID值后可以保证,在改动对象类后仍然可以读取以前储存的序列化流,因为反序列化时需要和对象类的class文件的id匹配,而不生成ID会导致每次修改对象类,id都变,于是匹配不上无法读取,报错

(3)注意问题:
    不想序列化的成员变量,用transient关键字声明
    private transient int age; 
    这样,年龄就不会被序列化,将以该类型的默认值序列化

Properties

(1)是一个集合类,Hashtable的子类

(2)特有功能
    A:public Object setProperty(String key,String value)
    B:public String getProperty(String key)
    C:public Set<String> stringPropertyNames()

(3)和IO流结合的方法
    把键值对形式的文本文件内容加载到集合中
    public void load(Reader reader)
    public void load(InputStream inStream)

    把集合中的数据存储到文本文件中
    public void store(Writer writer,String comments)
    public void store(OutputStream out,String comments)

NIO

(1)JDK4出现的NIO,对以前的IO操作进行了优化,提高了效率。但是大部分我们看到的还是以前的IO
    NIO使用了不同的方式来处理输入输出,采用内存映射文件的方式,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样来访问文件了,效率比IO高很多

(2)JDK7的NIO的使用  
    Path:路径
    Paths:包含了静态方法返回一个Path
    Files:操作文件的工具类,提供了常见的功能
    具体见我的另一篇文章

IO流练习

1.递归指定目录下某后缀名的文件

    /**
     * 递归指定目录下某后缀名的文件
     * 分析
     *  获取所有文件/目录 存为数组
     *  判断每个文件/目录是否是文件
     *  如果是文件夹,继续获取
     *  如果是文件,判断是否是XXX结尾,是就输出绝对路径
     *
     */
    public static void findXXX(String dir){
        File file = new File(dir);
        File[] files = file.listFiles();

        for (File x:files){
            if (x.isFile()){
                if (x.getName().endsWith(".java")){//后缀名为java
                    System.out.println(x);
                }
            }else {
                //如果是文件夹,则再次调用方法,把该文件夹的绝对路径传进去
                findXXX(x.getAbsolutePath());
            }
        }
    }

2.删除某目录下所有文件及文件夹

    /**
     * 删除某目录下所有文件及文件夹
     * @param dir
     */
    public static void deleteXXX(String dir){
        File file = new File(dir);
        File[] files = file.listFiles();

        if (files != null){
            for (File x:files){
                if (x.isFile()){
                    System.out.println(x+" --已删除");
                    x.delete();
                }else {
                //如果是文件夹,则再次调用方法,把该文件夹的绝对路径传进去
                    findXXX(x.getAbsolutePath());
                }
            }

        //第一个for删除了所有文件 接下来就是删除所有文件夹
            for (File x:files){
                System.out.println(x+" --已删除");
                x.delete();
            }
        }
    }

3.在字节输出流中加入异常处理

    /**
     * 加入异常处理的字节输出流
     */
    public static void IOExceptionDemo() {
        FileOutputStream file = null ;
        //一起处理
        try {
            file = new FileOutputStream("12.txt");
            file.write("sdfq".getBytes());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            //为了保证close一定会执行 所以放到finally
            //如果file不为null才需要close   如果目录不存在等情况导致创建file失败,file为null,此时再进行close就会空指针异常
            if (file != null) {
                try {
                    file.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

4.复制文件

    public static void copyFile(String input,String output) throws IOException {
        FileInputStream in = new FileInputStream(input);
        FileOutputStream out = new FileOutputStream(output);

//        int content ;
//        while( (content = in.read()) != -1 ){
//            out.write(content);
//        }
        //一次读取一个字节数组
        byte[] arr = new byte[1024];
        int length ;
        while ( (length = in.read(arr)) !=-1 ){
            out.write(arr,0,length);
        }

        out.close();
        in.close();
    }

5.BufferedOutputStream BufferedInputStream应用

    /**
     * BufferedOutputStream BufferedInputStream应用
     * 字节流复制文件一共四种方法:
     *      1.字节流一次读取一个字节 copyFile             74345ms
     *      2.字节流一次读取一个字节数组 copyFile            209ms
     *      3.高效字节流一次读取一个字节  copyBigFile       1330ms
     *      4.高效字节流一次读取一个字节数组 copyBigFile     149ms
     */
    public static void copyBigFile(String input,String output) throws IOException{

        BufferedInputStream in = new BufferedInputStream(new FileInputStream(input));
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(output));

//        int length ;
//        while ((length = in.read())!=-1){
//            out.write(length);
//        }
        int length;

        byte[] arr = new byte[1024];
        while ((length = in.read(arr))!=-1){
            out.write(arr,0,length);
        }

        out.close();
        in.close();
    }

6.字符流Demo

    /**
     * 字符流  Reader Writer 都只是用于txt文本文件  其他格式请用InputStream/Outputstream
     */
    public static void ziFuCopy(String input,String output) throws IOException{
//        BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(input)));

        //上面的太长了,以下采用 FileReader 使用本地默认编码,不用指定编码,省事
        BufferedReader in = new BufferedReader(new FileReader(input));
        BufferedWriter out = new BufferedWriter(new FileWriter(output));

        int length;
        char[] arr = new char[1024];
        while ((length = in.read(arr)) !=-1){
            out.write(arr,0,length);
        }
//        //一次读取一行 效率低于数组
//        String line ;
//        while((line = in.readLine()) != null){
//            out.write(line);
//            out.newLine();
//        }

        out.close();
        in.close();
    }

7.转换流Demo

    /**
     * 转换流
     * 读取
     * 以指定编码格式读取文件File
     */
    public static void convert(String input,String output) throws IOException{

        InputStreamReader in = new InputStreamReader(new FileInputStream(input),"UTF-8");
        OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(output),"UTF-8");

        int length = 0;
        char[] arr = new char[1024];
        while ( (length = in.read(arr)) != -1 ){
            out.write(arr,0,length);
//        out.flush(); flush刷新缓冲区 强制把数据写入  一般不用,写巨量文件的才用
        }


        in.close(); //close自带flush功能
        out.close();
    }

8.已知s.txt中有这个字符串”krjqoipfhasbckqekjda”,要求从s.txt中读取数据内容,排序后存入t.txt

代码就不写了,说下步骤
步骤:
BufferedReader读取文件内容  String content接收内容
转为字符数组 content.toCharArray()
排序 Arrays.sort(arr)
转为字符串String s = new String(arr)
写入t.txt  out.write(s)
去重的话用Set集合

9.键盘录入5个学生数据(姓名,语数外成绩),按照总分从高到低存入文本文件

    public static void saveScore(String dest) throws IOException{
        //TreeSet可排序, 匿名内部类实现Comparator接口
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s2.getSumScore()-s1.getSumScore();

                int num2 = num == 0? s2.getName().compareTo(s1.getName()) : num;
                int num3 = num2 ==0?s2.getZhCH() - s1.getZhCH():num2;
                int num4 = num3 ==0?s2.getMath()-s1.getMath():num3;
                int num5 = num4 ==0?s2.getEn()-s1.getEn():num4;
                return num5;
            }
        });


        for (int i =0;i<5;i++) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第"+(i+1)+"个学生姓名");
            String name = sc.nextLine();
            System.out.println("请输入第"+(i+1)+"个学生语文成绩");
            int zhCN = sc.nextInt();
            System.out.println("请输入第"+(i+1)+"个学生数学成绩");
            int math = sc.nextInt();
            System.out.println("请输入第"+(i+1)+"个学生英语成绩");
            int en = sc.nextInt();
            Student s = new Student(name,zhCN,math,en);
            ts.add(s);
        }
        //写数据
        BufferedWriter out = new BufferedWriter(new FileWriter(dest));
        out.write("姓名\t语文成绩\t数学成绩\t英语成绩\t总分");
        out.newLine();


        for (Student stu:ts){
            out.write(stu.getName()+"\t"+stu.getZhCH()+"\t"+stu.getMath()+"\t"+stu.getEn()+"\t"+stu.getSumScore());
            out.newLine();
        }

        out.close();
        System.out.println("学生信息存储完毕");
    }

10.复制多级文件/文件夹

    public static void copyMutiFolder(String filename, String dest) throws IOException{
        //创建File对象
        File readFile = new File(filename);
        File writeFile = new File(dest);

        //判断目的地是否存在 不存在就创建
        if (!writeFile.exists()){
            writeFile.mkdirs();
        }

        //先判断数据源是文件还是文件夹,是文件夹则读取路径下所有文件,存为File数组...
        if (readFile.isDirectory()) {
            //读取路径下所有文件,存为File数组
            File[] fileArray = readFile.listFiles();

            //创建目的地文件夹对象
            File newFolder = new File(writeFile,readFile.getName());
            //创建目的地文件夹
            newFolder.mkdir();

            //遍历数组 递归
            for (File file : fileArray) {
                copyMutiFolder(file.getAbsolutePath(),newFolder.getAbsolutePath());
            }

        //数据源是文件,直接复制,调用之前写好的方法
        }else {
            //创建目的地文件对象
            File newFile = new File(dest,readFile.getName());
            //复制文件
            IODemo.copyBigFile(filename,newFile.getAbsolutePath());
        }
    }

11.复制指定目录下指定后缀名文件,并修改后缀名

    /**
     * 复制指定目录下指定后缀名文件,并修改后缀名
     * 方法1
     * 一个一个判断是否为xxx后缀,是 就用IO流读写到目的地,写的过程中直接改名
     */
    public static void copyFileXXX(String filename, String dest,String xxx,String destXXX) throws IOException{

        File file = new File(filename);
        //转换为File数组
        //过滤器过滤
        final String xxxx = xxx;
        File[] files = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return new File(dir,name).isFile() && name.endsWith(xxxx);
            }
        });

        //判断目的地是否存在 不存在就创建
        File destFile = new File(dest);
        if (!destFile.exists()){
            destFile.mkdir();
        }

        //遍历
        if (files != null) {
            for (File x : files) {
                BufferedInputStream in = new BufferedInputStream(new FileInputStream(x.getAbsoluteFile()));

                //改名
                String name = x.getName();
                //截取原文件名并拼上新后缀
                String newName = name.substring(0,name.length()-xxx.length())+destXXX;

                BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest + "/" + newName));

                int length;

                byte[] arr = new byte[1024];
                while ((length = in.read(arr)) != -1) {
                    out.write(arr, 0, length);
                }

                out.close();
                in.close();
            }
        }
    }
    /**
     * 复制指定目录下指定后缀名文件,并修改后缀名
     * 方法2
     * 先过滤出来目标后缀名文件,再IO流复制到目的地,然后再改名
     * 缺点 会把目的地目录下的原xxx后缀名文件也改成新的,因为是在目的地改名
     */
    public static void copyFile1XXX(String filename, String dest,String xxx,String destXXX) throws IOException{
        File file = new File(filename);

        File destFile = new File(dest);
        if (!destFile.exists()){
            destFile.mkdir();
        }

        //过滤后缀名
        final String xxxx = xxx;
        File[] fileList = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return new File(dir,name).isFile() && name.endsWith(xxxx);
            }
        });

        //复制, 定义好新的目的地File对象 传入以前写好的复制方法中
        for (File x:fileList){
            String name = x.getName();
            File newFile = new File(dest,name);

            IODemo.copyBigFile(x.getAbsolutePath(),newFile.getAbsolutePath());
        }

        //改名
        File[] destFileList = destFile.listFiles();
        for (File x:destFileList){
            String name = x.getName();
            String newName = name.replace(xxx,destXXX);
            File newFile = new File(dest,newName);
            //同目录下是改名,不同目录下是剪切
            x.renameTo(newFile);
        }
    }

12.复制单级文件夹

    public static void copyFolder(String FolderName,String dest) throws IOException {
        //转换为File数组
        File file = new File(FolderName);
        File[] files = file.listFiles();

        //判断目标目录是否存在 不存在就创建
        File destFile = new File(dest);
        if (!destFile.exists()){
            destFile.mkdir();
        }

        if (files != null) {
            for (File x : files) {

                BufferedInputStream in = new BufferedInputStream(new FileInputStream(x.getAbsoluteFile()));
//                File newFile = new File(dest,x.getName());
//                BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(newFile));
                BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest+"/"+x.getName()));

                int length;

                byte[] arr = new byte[1024];
                while ((length = in.read(arr))!=-1){
                    out.write(arr,0,length);
                }

                out.close();
                in.close();
            }
        }
    }

13.某个文本文件储存了几个人名,设计一个方法随机获取一个人名

    public static String getName(String filepath) throws IOException{
        BufferedReader in = new BufferedReader(new FileReader(filepath));
        ArrayList<String> list = new ArrayList<>();

        String line;
        while ((line = in.readLine()) != null){
            list.add(line);
        }

        in.close();

        Random num = new Random();

        return list.get(num.nextInt(list.size()));
    }

14.从文本中读取数据并存到集合中,遍历集合

    public static void saveToList(String filepath) throws IOException{
        BufferedReader in = new BufferedReader(new FileReader(filepath));
        ArrayList<String> list = new ArrayList<>();

        String line;
        while ((line = in.readLine()) != null){
            list.add(line);
        }

        in.close();
        for (String x:list){
            System.out.println(x);
        }
    }

15.把ArrayList中数据储存在文本中

    public static void saveList(ArrayList list,String dest) throws IOException {
        BufferedWriter out = new BufferedWriter(new FileWriter(dest));
        for (Object x:list){
            out.write(String.valueOf(x));
            out.newLine();
        }
        out.close();
    }

16.批量改名

import java.io.File;
import java.io.FilenameFilter;

/**
 * Created by mo on 15/11/12.
 * 批量改名
 * 把所有视频文件 由  三国演义_003_董卓.avi  改为  003_董卓.avi
 */
public class changeName {
    public static void main(String[] args) {

        File dir = new File("/Users/mo/FileTest");

        File[] avi = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return new File(dir,name).isFile() && name.endsWith(".avi");
            }
        });

        for (File x:avi){
            //查找第一个_  并截取_后三个字符
            int index = x.getName().indexOf("_");
            String filename = x.getName().substring(index+1,index+4);

            StringBuilder sb = new StringBuilder();

            sb.append(filename).append("_");
            //查找第二个_ 并截取_后两个字符
            index = x.getName().lastIndexOf("_");
            String intro = x.getName().substring(index+1,index+3);

            //拼上.avi
            sb.append(intro).append(".avi");

            //重命名
            x.renameTo(new File("/Users/mo/FileTest",sb.toString()));

            //不用SB 用String的concat方法拼接也可
        }


    }
}

17.判断Users/Download下是否有.mkv文件,有则输出文件名

import java.io.File;
import java.io.FilenameFilter;

/**
 * Created by mo on 15/11/12.
 *
 * 判断Users/Download下是否有.mkv文件,有则输出文件名
 * 方法一:判断是否为文件,再用endsWith方法判断是否为mkv结尾,很简单,
 *       这里不再演示
 * 方法二
 * 在获取的时候就已经是满足条件的了,直接输出就行
 * 实现方法:需实现FilenameFilter接口
 */
public class isJPG2 {
    public static void main(String[] args) {

        File down = new File("/Users/mo/Downloads");

        String[] list = down.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return new File(dir,name).isFile() && name.endsWith(".mkv");
            }
        });

        for (String s:list){
            System.out.println(s);
        }
    }
}

18.用Reader模拟BufferedReader的readLine功能(一次读取一行,只返回内容,不返回换行符)

import java.io.IOException;
import java.io.Reader;

/**
 * Created by mo on 15/11/16.
 *
 * 需求:用Reader模拟BufferedReader的readLine功能(一次读取一行,只返回内容,不返回换行符)
 *
 */

public class MyBufferedReader {
    private Reader r;

    public MyBufferedReader(Reader r) {
        this.r = r;
    }

    public void close() throws IOException{
        this.r.close();
    }

    //一次读取一个字符,用临时变量储存上一个字符,临时变量选择StringBuilder
    public String readLine() throws IOException{
        int ch;
        StringBuilder sb = new StringBuilder();
        while ((ch=r.read()) != -1){
            if (ch == '\r'){
                continue;
            }
            if (ch == '\n'){
                return sb.toString();
            }else {
                sb.append((char)ch);
            }
        }

        //以上代码都是每次遇到换行符才结束,如果文本最后不是换行符,读到末尾不是换行符,返回-1,会直接跳出循环,然后返回null而不是存好数据的sb
        //所以为了防止数据丢失,此处添加代码,判断sb长度,不为0则返回sb,为0说明文本为空
        if (sb.length() >0){
            return sb.toString();
        }
        return null;
    }
}
/**
 * Created by mo on 15/11/16.
 * 测试MyBufferedReader
 */
public class MyBufferedReaderTest {
    public static void main(String[] args) throws IOException {
        MyBufferedReader in = new MyBufferedReader(new FileReader("/Users/mo/Downloads/mac赠品.txt"));

        String line;
        while ((line=in.readLine()) != null){
            System.out.println(line);
        }

        in.close();
    }
}

19.自定义类模拟LineNumberReader的获取行号功能

import java.io.IOException;
import java.io.Reader;

/**
 * Created by mo on 15/11/16.
 *
 * 用继承的方法
 */
public class MyLineNumberReader2 extends MyBufferedReader{
    private Reader r;
    private int LineNumber;

    public MyLineNumberReader2(Reader r) {
        super(r);
    }

    public void setLineNumber(int lineNumber) {
        LineNumber = lineNumber;
    }

    public int getLineNumber() {
        return LineNumber;
    }

    @Override
    public String readLine() throws IOException {
        LineNumber++;
        return super.readLine();
    }

}

20.登陆注册案例,用户信息加密储存

import java.io.*;
import java.util.Scanner;

/**
 * Created by mo on 15/11/16.
 *
 * 登陆注册案例
 * 加密储存
 *
 * 应该分包,便于以后维护
 */
public class SignUpAndLogIn {
    //创建储存用户名密码的文件
    private static File file = new File("userdata.txt");
    static {
        if (!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                System.out.println("创建数据库失败");
            }
        }

    }

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

    /**
     * 开始界面
     * @throws IOException
     */
    public static void welcome() throws IOException {

        System.out.println("--------------------");
        System.out.println("欢迎,注册请按1,登陆请按2,退出请按3");
        Scanner sc = new Scanner(System.in);

        int num = sc.nextInt();
        switch (num){
            case 1:
                signUp();
                break;
            case 2:
                logIn();
                break;
            case 3:
                System.exit(0);
                break;
            default:
                System.out.println("您输入的数据有误");
                welcome();
                break;
        }
    }

    /**
     * 登陆界面
     * @throws IOException
     */
    private static void logIn() throws IOException {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名");
        String name = sc.nextLine();
        System.out.println("请输入密码");
        String key = sc.nextLine();


        if (match(name,key)){
            System.out.println("开始游戏");
        }else {
            System.out.println("用户名或密码不对,回到开始界面");
            welcome();
        }
    }

    /**
     * 将用户名密码与数据库储存的进行匹配
     * @param name 用户名
     * @param key 密码
     * @return 匹配成功,返回true
     * @throws IOException
     */
    private static boolean match(String name, String key) throws IOException {
        boolean flag = false;

        BufferedReader in = new BufferedReader(new FileReader(file));
        String line;

        String user = codeKey(name+"\t")+codeKey(key);

        while ((line=in.readLine()) != null){
            if (line.equals(user)){
                flag = true;
                break;
            }
        }

        in.close();
        return flag;
    }

    /**
     * 注册界面
     * @throws IOException
     */
    private static void signUp() throws IOException {
        System.out.println("请输入要注册的用户名");
        Scanner sc = new Scanner(System.in);
        String username = sc.nextLine();
        System.out.println("请输入要注册的密码");
        String password = sc.nextLine();
        System.out.println("请再次输入要注册的密码");
        String password2 = sc.nextLine();

        //先检测两次输入的密码是否相同
        if (password.equals(password2)){
            //再检测输入的用户名是否已存在
            String onlyname = codeKey(username+"\t");
            if (!findUser(onlyname)){
                //用户名不存在,开始储存用户名密码
                BufferedWriter out = new BufferedWriter(new FileWriter(file,true));

                String key =codeKey(username+"\t")+codeKey(password);

                out.write(key);
                out.newLine();
                out.close();

                System.out.println("注册完毕,返回开始界面");
                welcome();
            }else {
                System.out.println("用户名已存在!");
                welcome();
            }
        }else {
            System.out.println("两次输入的密码不一致");
            welcome();
        }


    }

    /**
     * 将用户名与数据库中的用户名进行匹配
     * @param onlyname
     * @return 找到存在的用户名就返回true
     * @throws IOException
     */
    private static boolean findUser(String onlyname) throws IOException {
        boolean flag = false;

        String username = codeKey(onlyname);

        BufferedReader in = new BufferedReader(new FileReader(file));
        String line;

        while ((line=in.readLine()) != null){
            if (line.startsWith(username)){
                flag = true;
                break;
            }
        }

        return flag;
    }

    /**
     * 加密方法
     * @param s
     * @return
     */
    private static String codeKey(String s) {
        char[] arr = s.toCharArray();
        int[] keyarr = new int[arr.length];
        for (int i = 0;i<arr.length;i++){
            keyarr[i] =  (arr[i]+5)%10;
        }
        keyarr[0] = keyarr[0]^keyarr[arr.length-1];
        keyarr[arr.length-1] = keyarr[0]^keyarr[arr.length-1];
        keyarr[0] = keyarr[0]^keyarr[arr.length-1];

        StringBuilder sb = new StringBuilder();
        for (int x:keyarr){
            sb.append(x);
        }
        return sb.toString();
    }


}

CharArrayReader CharArrayWriter的基本用法

CharArrayReader 是一个把字符数组作为源的输入流的实现。该类有两个构造方法: –CharArrayReader(char array[ ]) –CharArrayReader(cha...

黑马程序员——Java基础---异常,IO流,File类

-----------android培训、java培训、java学习型技术博客、期待与您交流!------------ 一、异常 (一)异常概述 1. 异常:异常就是Java程序在运行过程中...

黑马程序员——Java基础——IO流笔记(File使用示例)

------- android培训、java培训、期待与您交流! ----------

黑马程序员——高新技术---Java基础-IO流_File类,递归思想

java.io.File类 File:文件和目录路径名的抽象表示形式   1,它代表磁盘上的文件或目录 2,它内部封装了一些方法,可以查看此文件或目录的一些信息: 文件/目录是否存在,判断文件还是目录...

黑马程序员——Java IO流(二)之流操作规律总结、File类、Properties类、序列流等

-----------android培训、java培训、java学习型技术博客、期待与您交流!------------ 六、流操作规律总结  1.明确源和目的:   源:    字符流:FileRea...

黑马程序员——Java基础---IO(二)--File类、Properties类、打印流、序列流、其他类

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 第一讲   File类 一、概述 1、File类:文件和目录路径名的抽象表示形式。 2、特点: ...

黑马程序员——Java基础---IO流(File类、Properties类、其他流)

File类: 用来将文件或者文件夹封装成对象。 方便于对文件或文件夹的属性信息进行操作。 (流只能操作数据,而想要操作数据被封装的文件的信息必须用File对象。) File对象可以作为参数传递给流的构...

黑马程序员——Java基础----IO(File类、Properties类、打印流、序列流、合并流)(3)

-----------android培训、java培训、java学习型技术博客、期待与您交流!------------                                        ...

黑马程序员——Java基础---IO(二)--File类、Properties类、打印流、序列流(合并流)

第一讲     File类 一、概述 1、File类:文件和目录路径名的抽象表现形式 2、特点:         1)用来将文件或文件夹封装成对象         2)方...

黑马程序员——Java基础---IO(二)--File类、Properties类、打印流、序列流(合并流)

-----------android培训、java培训、java学习型技术博客、期待与您交流!------------  第一讲     File类 一、概述 1、File类:文件和目录路径名的抽象表...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【黑马程序员】异常,File类,IO流——Java复习笔记
举报原因:
原因补充:

(最多只允许输入30个字)