零基础学习java------day16-----文件,递归,IO流(字节流读写数据)

1.File

1.1 构造方法(只是创建已经存在文件的对象,并不能创建没有的文件)

(1)public File(String pathname)

(2)public File(String parent, String child)

(3)public File(File parent, String child)

public class FileDemo1 {
    public static void main(String[] args) {
        File f = new File("e:/a/b");
        System.out.println(f.exists()); //true
        File f1 = new File("e:/G09 result/","H2O"); //此处result后的“/”号有无都可以
        System.out.println(f1.exists()); //true
        File f2 = new File(f1,"H2O.out");
        System.out.println(f2.exists());//true
    }
}

1.2 File类成员方法

1.2.1 创建删除重命名功能

(1)创建功能  

  public boolean createNewFile()       创建文件
  public boolean mkdir()                     创建单层文件夹
  public boolean mkdirs()                   创建多层文件夹

(2)删除功能

  public boolean delete()                    删除文件或文件夹(文件夹中有内容无法删除)

(3)重命名功能 

  public boolean renameTo(File dest)   重命名(移动)

public class FileDemo2 {
    public static void main(String[] args) {
        try {
            File f = new File("e:/G09 result/H2O/t.txt");//创建文件的时候,目录必须存在
            boolean b = f.createNewFile();
            new File("e:/a").mkdir(); //在盘创建了a文件夹
            new File("e:/a/b/c/d").mkdirs();//创建了多层文件夹,此对象代表d这个文件夹
            File f1 = new File("e:/123");
            f1.createNewFile();//得到的是一个文件,文件可以没有后缀名
            File f2 = new File("e:/789.txt");
            f2.mkdir();//得到的是一个文件夹
            f1.delete();
            f2.delete(); // 如果文件夹中有内容是不能被删除的
            f.renameTo(new File("d:/haha.txt")); //将e:/G09 result/H2O/t.txt文件移动到d盘,并重命名为haha.txt
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

1.2.2 判断功能

(1)public boolean isDirectory():是否是目录

(2)public boolean isFile():是否是文件

(3)public boolean exists():是否存在

(4)public boolean canRead():是否可读

(5)public boolean canWrite():是否可写

(6)public boolean isHidden():   是否隐藏

public class FileDemo3 {
    public static void main(String[] args) {
        File f = new File("e:/a");
        System.out.println(f.exists()); //true
        System.out.println(f.isDirectory());//true
        System.out.println(f.isFile());//false
        System.out.println(f.canRead()); //true
        System.out.println(f.canWrite()); //true
        System.out.println(f.isHidden()); //false
    }
}

 

1.2.3  获取功能

a . 基本获取功能

(1)public String getAbsolutePath():获取绝对路径

(2)public String getPath():              获取相对路径

(3)public String getName():            获取文件名

(4)public long  length():                  获取字节数

(5)public long lastModified:            获取最后修改时间

public class FileDemo4 {
    public static void main(String[] args) throws IOException {
        File f1 = new File("忽然.txt");
        f1.createNewFile();
        System.out.println(f1.getAbsolutePath());//E:\development\workspace\java\javase\javase\忽然.txt
        System.out.println(f1.getPath());//忽然.txt
        System.out.println(f1.getName());//忽然.txt
        System.out.println(f1.length());
        System.out.println(f1.lastModified());//1566540753201
        //先将long类型的毫秒值转为date类型的时间,然后再讲此时间转为特定格式的时间
        System.out.println(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date(f1.lastModified())));
    }
}

b . 高级获取功能

(1)public String[ ]  list():                    获取所有子文件名称(返回值类型为字符串数组)

(2)public File[ ] listFiles():                获取所有子文件对象  (返回值类型为文件类型数组)        

public class FileDemo5 {
    public static void main(String[] args) {
        File f = new File("E:\\exercise");
        System.out.println(f.list());  //[Ljava.lang.String;@279f2327
        System.out.println(Arrays.toString(f.list()));//这样转化后就能打印数组了
        File[] listFiles = f.listFiles();
        System.out.println(f.listFiles());//[Ljava.io.File;@2ff4acd0,需要将其遍历出来
        for(File file:listFiles) {
            System.out.println(file);
        }
    }
}

 

练习  查询单层文件夹下所有以后缀名(.jpg))结尾的文件,此处,我要查询的文件夹如下:

法一:

public class FindFile {
    public static void main(String[] args) {
        getFile("E:\\exercise",".jpg");
    }
    public static void getFile(String path,String suffix) {
        File f = new File(path);
        File[] listFile = f.listFiles();
        for (File file : listFile) {
       //除了判断后缀,还要判断是不是文件,有大写文件的话,转为小写
if(file.isFile() && file.getName().toLowerCase().endsWith(suffix)) { System.out.println(file.getAbsolutePath()); } } } }

法二(使用过滤器)

 

public class FindFile {
    public static void main(String[] args) {
        getFile("E:\\exercise",".jpg");
    }
    public static void getFile(String path,String suffix) {
        File f = new File(path);
     // 带有过滤器为参数的listFiles方法,这里使用了匿名函数来创建过滤器对象
        File[] files = f.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                File f1 = new File(dir,name);
                if(f1.isFile()&&f1.getName().toLowerCase().endsWith(suffix)) {
                    return true;
                }
                return false;
            }
        });
        for (File file : files) {
            System.out.println(file.getAbsolutePath());
        }
    }        
}

 

 2. 递归

 2.1 递归的思想概述

   方法定义中调用本身的现象。

 注意事项:

  递归要有出口,否则就是死递归;次数不能太多,否则内存会溢出;构造方法不能递归使用

2.2 递归的思想

  找到出口;找到规律

2.3 递归练习

1. 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到三个月后每个月又生一对兔子,假如兔子都不死,问第十个月兔子对数为多少?

本题的本质是斐波那契数列,如下图:

第一个月时,有一对兔子(刚生下来为小兔子,过了一个月后就变成大兔子,再过一个月就能生小兔子),第二个月是总的兔子数还是为1,但此时小兔子变成了大兔子,第三个月大兔子生了一对小兔子,所以第三个月有2对兔子(一大一小),依次类推下去可得斐波那契数列(正如图上的sum行)

public class BornRabbit {
    public static void main(String[] args) {
        System.out.println("10个月后兔子对数:"+ rabbitNumber(10));
    }
    public static int rabbitNumber(int month) {
        if(month==1 || month==2) {
            return 1;
        }else {
            return rabbitNumber(month-1)+rabbitNumber(month-2);
        }
    }
}

 

2.小猴子第一天摘下若干桃子,当即吃掉一半,又多吃一个,第二天早上又将剩下的桃子吃掉一半,又多吃一个,以后每天早上吃前一天剩下的一半以及另一个。到第10天早上猴子想再吃时发现,只剩下一个桃子了,问第一天猴子共摘了多少个桃子?

 规律如下图

public class Monkey {
    public static void main(String[] args) {
        System.out.println(eatPeach(1));
    }
    public static int eatPeach(int day) {
        if(day==10) {
            return 1;
        }else {
            return 2*(eatPeach(day+1)+1);
        }
    }
}

 

 3. 递归查找文件(文件夹有多层)

public class RecursionFindFiles {
    public static void main(String[] args) {
        findAllFiles("E:/exercise",".jpg");
    }
    public static void findAllFiles(String path, String suffix) {
        File f = new File(path);
        //如果传入的路径为文件
        if(f.isFile()) {
            if(f.getName().toLowerCase().endsWith(suffix));{
                System.out.println(f.getAbsolutePath());
            }
        }else {   //是文件
            //获取所有子文件    
            File[] listFiles = f.listFiles();
            if(listFiles!=null && listFiles.length>0) {
                for (File file : listFiles) {
                    findAllFiles(file.getAbsolutePath(),suffix);
                }
            }
        }
    }
}

 变形:递归删除文件夹以及其中的所有文件

public class RecursionDelete {
    public static void main(String[] args) {
        findAllFiles("E:/a");
    }
    public static void findAllFiles(String path) {
        File f = new File(path);
        //如果传入的路径为文件
        if(f.isFile()) {
            f.delete();
        }else {   //是文件
            //获取所有子文件    
            File[] listFiles = f.listFiles();
            if(listFiles!=null && listFiles.length>0) {
                for (File file : listFiles) {
                    findAllFiles(file.getAbsolutePath());
                }
            }
            f.delete();
        }
    }
}

 

3. IO流

3.1 IO流的概述

IO流用来处理设备之间的数据传输(上传文件和下载文件),Java对数据的操作是通过流的方式,此外java用于流的操作对象都在IO包中

 

3.2 IO流的分类

(1)按照数据流向

  输入流: 读入数据

  输出流:写出数据

(2)按照数据类型

  字节流,字符流

  一个汉字若按字节流处理,需要处理3次(utf8编码中一个汉字3个字节),若用字符流来处理只需要一次,但字符流一般只能用来处理文本文件,如图片就不能处理,但字节流(任何文件都可以处理)可以,所以字节流较字符流使用范围更广

(3)什么情况下使用哪种流呢?

  如果数据所在的文件通过windows自带的记事本打开并能读里面的内容,就用字符流。其他用字节流

 

3.3 IO流常用基类

(1)字节流的抽象基类:

  InputStream,OutputStream

(2)字符流的抽象基类

  Reader  ,     Writer

注意:由这四个类派生出来的子类名称都是以其父类名作为类名的后缀

如:InputStream的子类FileInputStream

  Reader的子类FileReader

 

3.4 字节流写数据(FileOutputStream)

3.41 FileOutputStream的构造方法:

(1)FileOutputStream(File, file)

(2)FileOutputStream(String name)   //一般用第二种,方便点

3.4.2  FileOutputStream的成员方法

(1)public void write(int b)

(2)public void write(byte[ ] b)

(3)public void write(byte[ ] b,int  off, int len)  

public class FileOutputStreamDemo {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("d:/haha.txt");
            fos.write(97);
            fos.write(98);
            fos.write(99);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {   // 关流,即关闭文件
            if(fos != null) {  //此处要判断下不为null
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
运行结果:d盘中的haha.txt写入了abc

但是怎样写入一字符串呢?=====>将字符串转成Byte,改用第二或第三个成员方法

fos.write("忽然就流出泪来".getBytes());//此代码紧接着fos.write(99)哪行写
fos.write("哈哈忽然间想要听到他的声音".getBytes(),6,33);//后面两个int值第一个为偏移量,第二个为从偏移量位置开始写入数据的长度,这里长度以Byte为单位

运行结果:abc忽然就流出泪来,忽然间想要听到她的声音

 

有上面代码可知,手动关流写起来比较麻烦,JDK1.7以后提供了自动关流的方法,格式如下:

try(流的定义语句){

}catch(){

}

 

注意:另外创建一个流,并将数据写入原先有数据的文件,会将原先的数据覆盖掉)(如上面例子中haha.txt原先若有内容则会覆盖掉),但一个流中依次写入的数据,后者写入不会覆盖前者写入的数据

让其不覆盖院线数据的方法是:在利用构造方法创建对象时传两个参数,除了路径再传个True(默认是false),这样就不会覆盖原先的数据了

  当将上诉第5行代码换成如下代码时,运行多次程序,会得到多句同样的结果,不会覆盖(原先无论运行几次都是一句话)

fos = new FileOutputStream("d:/haha.txt",true);

 

3.5 字节流读取数据(FileInputStream)

3.5.1  FileInputStream的构造方法

(1)FileInputStream(File file)

(2)FileInputStream(String)  //一般用第二种,方便点

3.5.1  FileInputStream的成员方法

(1)public int read()         每次读取一个字节并 返回读取一个字节所对应的编码

(2)public int read(byte[] b)   :每次读取数组的长度个字节,返回读回来的长度(实际读取的内容)

第二个成员方法返回的是buffer(缓存区)  b的长度          

 

 1 public class FileInputStreamDemo {
 2     public static void main(String[] args) {
 3         try(
 4                 FileInputStream fis = new FileInputStream("d:/a.txt"); //啊的内容为 ab
 5                 ){
 6             System.out.println(fis.read()); //97
 7             System.out.println(fis.read());//98
 8             System.out.println(fis.read());//-1 可见当没内容可读取的时候,返回的是-1
 9         } catch (Exception e) {
10             e.printStackTrace();
11         }
12     }
13 }

 若将a.txt的内容改为abc大,那么这个中文字“大”怎么读取出来呢?,代码如下

在上面第8行代码后加如下代码

1     int d = fis.read();
2     int e = fis.read();
3     int f = fis.read();
4     // 创建一个Bytes数组,将上面三个字节平成一个byte数组
5     byte[] bs = new byte[] {(byte)d,(byte)e,(byte)f};
6     System.out.println(bs);//[B@279f2327
7     System.out.println(new String(bs));//

 这样一个字节一个字节读取很费经,可以直接1kb的读取,要想1字节的话可以用for循环读取,循环控制条件就是读取数据返回值为-1

若a文件内容还是为”abc大",这次换成一次性读取1kb,代码如下

public class FileInputStreamDemo {
    public static void main(String[] args) {
        try(
                FileInputStream fis = new FileInputStream("d:/a.txt"); //啊的内容为 ab
                ){
            System.out.println(fis.read()); //97
            System.out.println(fis.read());//98
            System.out.println(fis.read());//99
            byte[] bs1 = new byte[1024]; //数组在每个位置的默认值为0,转为字符串就是空格
            fis.read(bs1);
            System.out.println(new String(bs1)); //将byte数组转为字符串打印出来
            System.out.println(new String(bs1).length());//1022 字符串的长度,说明其将空格也读取出来了
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字符串长度为1022的由来:空格长度为1024-3=1021,一个汉字(大)长度为1,所以字符串长度为1022+1=1023

怎样让其读取的内容为实际的长度呢?======>让第二个成员方法接收返回值,其返回的是真实的长度

如将上面代码fis.read(bs1)改为System.out.println(fis.read(bs1)),打印的结果为3,可见返回的是真实读取的字节数

下例中把文件的内容为:没有人在热河里谈恋爱
public class FileInputStreamDemo1 {
    public static void main(String[] args) {
        try(
                FileInputStream fis = new FileInputStream("d:/b.txt"); //啊的内容为 ab
                ){
            byte[] bs1 = new byte[1024];
            int len;
            while((len = fis.read(bs1))!=-1) {
                System.out.println(new String(bs1,0,len));//没有人在热河里谈恋爱
                System.out.println(new String(bs1,0,len).length());//10
            }            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

由结果可知,读取的内容是实际的长度,并不会将空格也读出来

 

拷贝文件,比如将"E:/exercise/haha/天空之城.jpg"拷贝到"E:/exercise/haha/热河.jpg"

public class CopyFile {
    public static void main(String[] args) {
        try(
                FileInputStream fis = new FileInputStream("E:/exercise/haha/天空之城.jpg");
                FileOutputStream fos = new FileOutputStream("E:/exercise/haha/热河.jpg");
                ) {
            byte[] bs = new byte[1024];
            int len;
            while((len = fis.read(bs)) != -1) {  //读取数据,当返回值为-1时,表示读取完毕
                fos.write(bs,0,len);  //写入
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

posted @ 2019-08-22 22:47  一y样  阅读(232)  评论(0编辑  收藏  举报