黑马程序员——019——IO流④(File、递归、Properties、PrintWriter、合并流)

来源:互联网 发布:淘宝国际快递转运 编辑:程序博客网 时间:2024/05/16 19:43
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

File类
File类;
—流在操作的时候只有数据;
—现实中有很多种文件,就像人,所以抽象出一个类File,
——来进行统一的描述;
—对文件或者文件夹的属性信息进行操作
—弥补了流对文件操作的不足:
——流不能知道这个文件是不是可读还是可写的;
——流只能操作数据;
——想要操作对象必须要用File的对象;
实例代码:
————————————————————————————

File f1 = new File("a.txt")//a.txt不存在也可得到f1对象//可以将存在或者不存在的文件或者文件夹封装成对象;//————————————————————————————File f2 = new File("C:\\abc","a.txt")//c盘abc文件夹下的a.txt文件//上面这一句等于下面两句File d = new File("C:\\abc");File f3 = new File(d,"a.txt");//————————————————————————————//直接打印对象 是打印出其封装时候的构造参数//若构造参数是绝对路径那打印出来就是绝对路径//若是相对就打印相对的syso(f1);//a.txt,syso代表System.out.printlnsyso(f2);//C:\\abc\\a.txtsyso(f3);//C:\\abc\\a.txt

—————————————————————————————
File类有一个常量separator,可以帮助代码更好的跨平台,就像bufferedWriter的newLine一样:
在 UNIX 系统上,此字段的值为 ‘/’;在 Microsoft Windows 系统上,它为 ‘\’。
如果我们要指定C盘下文件夹abc下的“a.txt”文件,我们可以这样写:
—File f4 = new File(“c:”+File.separator+abc+File.separator+”a.txt”);
File类的常见方法;
—1.文件可以创建:
——调用底层资源,IO异常
——boolean createNewFile()
——在指定位置创建文件,如果存在则不创建,发会false
———和输出流不同的是输出流文件存在会覆盖;
——另外还有两个创建临时文件的方法:
———boolean createTempFile(),一个三个参数一个两个参数;
—2.删除
——boolean delete();删除失败返回false;
——boolean deleteOnExit();虚拟机退出的时候删除;
—3.判断(存在或者是文件还是文件夹)
——boolean exits();判断文件是否存在
——boolean isFile(),判断是否是文件
——boolean isDirectory(),判断是否是文件夹
———以上两个方法执行之前必须判断exits是否存在先!
——boolean isHidden(),判断是否隐藏
——boolean isAbsolute(),判断是否是绝对路径
—4.获取信息(名称,路径,大小等)
——String getName()获取文件名
——String getPath()获取到封装的路径
——String getAbsolutePath()获取到绝对路径,即使是不存在的文件
——File getAbsoluteFile() 获取到绝对路径,封装成文件对象了,即使是不存在的文件
——String getParent()获取文件的父目录
———返回的是绝对路径中的父目录,如果获取的是相对路径,返回null
———如果封装的时候相对路径中有上一层目录那么该目录就是返回结果例如:
————File f1 = new File(a.txt);//
————syso(f1.getParent());//null
————File f2 = new File(abc/a.txt);//
————syso(f2.getParent());//abc
——long lastModified(),返回上一次修改的时间
——long length(),返回由此抽象路径名表示的文件的长度。
boolean renameTo(File dest) 将文件移动到指定参数指定的文件处,若名字变了就变,没变就等于移动了;原来位置的文件没了;
—————————————————————————————
File类之listRoots方法
static File[] listRoots()
—静态方法,列出可用的文件系统根。
实例代码:
—————————————————————————————

import java.io.*;class Demo19_1{        public static void main(String[] args)        {                File[] files = File.listRoots();                for(File f : files)                {                        System.out.println(f);                }        }}

—————————————————————————————
执行结果:
这里写图片描述
—————————————————————————————
File类之列出文件列表方法
String[] list() 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 包括隐藏文件;
—调用这个方法的File对象必须要封装一个目录:否则会报空指针异常:
实例代码:
—————————————————————————————

import java.io.*;class Demo19_2{        public static void main(String[] args)        {                File f = new File("d:");                String[] names = f.list();                for(String s : names)                {                        System.out.println(s); //列出d盘下所有目录+文件名称                }        }}

—————————————————————————————
几个文件列出方法的总结:
—String[] list() 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
—File[] listFiles() 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
—File[] listFiles(FileFilter filter) 返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
—File[] listFiles(FilenameFilter filter) 返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
我们可以看到java.io.FilenameFilter 是一个接口
—其只有一个待实现的方法:
——boolean accept(File dir, String name)
———测试指定文件是否应该包含在某一文件列表中。
实例代码:使用FilenameFilter过滤出一个“D:\abc”目录下的所有rar文件
“D:\abc”目录下文件如下:
这里写图片描述
—————————————————————————————

import java.io.*;class Demo19_3{        public static void main(String[] args)        {                File f = new File("D:"+File.separator+"abc");                //采用匿名类的形式实现Filenamefilter                File[] files = f.listFiles(new FilenameFilter()                {                        //实现接口的方法                        public boolean accept(File dir, String name)                        {                                //只接受文件名字以“.rar”结尾的文件                                return name.endsWith(".rar");                        }                });                for(File ff : files)                {                        System.out.println(ff);                }        }}

—————————————————————————————
执行结果:
这里写图片描述
—————————————————————————————
—————————————————————————————
递归
递归,用通俗的话解释就是在一个方法内部有调用自己这个方法。
开发中也常常会用到的,它的使用当然也有一些需要注意的地方,我们先看两个旧的实例,我们现在用递归的方式来实现:
—①获取十进制数的二进制串;
—②计算1+2+3+…+n;
实例代码:
—————————————————————————————

class Demo19_4{        public static void main(String[] args)        {                toBin(6);//最终打印110                sopln();                toBin(8);//最终打印1000                sopln();                sop(getSum(3));//①最终打印6                sopln();        }        /*①获取十进制数的二进制串;*/        static void toBin(int num)        {                if(num>0)                {                        int o = num/2;                        int m = num%2;                        //递归,用继续调用自己操作商o,打印余数                        toBin(o);                        sop(m);                }        }        /*②计算1+2+3+...+n;*/        static int getSum(int n)        {                if(n==1)                        return 1;                return n+getSum(n-1);        }        static void sop(Object o)        {                System.out.print(o);        }        static void sopln(Object... o)        {                if(o.length==0)                        System.out.println();                else                        System.out.println(o[0]);        }}

—————————————————————————————
执行结果:
这里写图片描述
如果我们在①处往getSum中传入一个8000,就会内存溢出了,因为层层产生了太多的的方法而又没有及时结束,超过了栈的空间 就中导致了 内存溢出;
所以递归要注意:
—1.限定条件;
—2.要注意递归的次数,尽量避免内存溢出;
—————————————————————————————
接下来我们把File的几个方法串起来写一个综合小实例,就是模拟dos下的tree命令列出文件:
我们知道tree不仅能够把文件夹中的文件列出来,还能够把文件夹中的文件夹中的文件也列出来,甚至更深层的都列出来,这就用到递归了,接下来看实例代码:
—————————————————————————————

import java.io.*;class Demo19_5{        public static void main(String[] args)        {                treeDir(new File(                        "D:/apache-tomcat-6.0.43/webapps/day11/WEB-INF",0);        }        static void treeDir(File dir,int level)        {                sopln(getLevel(level)+dir.getName());                level++;                File[] files = dir.listFiles();                for(int i=0;i<files.length;i++)                {                        if(files[i].isDirectory())                                //若是文件夹继续递归,将起始分级数传进去                                treeDir(files[i],level);                        else                                //若是文件则分级打印出来                                sopln(getLevel(level)+files[i]);                }        }        /*根据传入的数量打印分隔符数量*/        static String getLevel(int level)        {                StringBuilder sb = new StringBuilder();                sb.append("|--");                for(int i=0;i<level;i++)                {                        //插入到最前端                        sb.insert(0,"|  ");                }                return sb.toString();        }        static void sop(Object o)        {                System.out.print(o);        }        static void sopln(Object... o)        {                if(o.length==0)                        System.out.println();                else                        System.out.println(o[0]);        }}

—————————————————————————————
注意:
—遍历的时候(不是删除的遍历,删除以外的遍历),最好避开隐藏文件或者文件夹,
——因为有些隐藏内容是系统帮我们加进去的,是我们不需要考虑的东西,我们可以在判断目录条件上与上一个条件:
———if(files[i].isDirectory() && !(files[i].isHidden()))//是文件夹并且不是隐藏的
—————————————————————————————
删除带内容的目录
win中,删除一个目录是从里面的开始往外删除的;
—对于空目录,直接调用delete方法即可,
—所以,这里也需要使用到递归了;
实例代码:
—————————————————————————————

import java.io.*;/*删除带内容的目录*/class Demo19_6{        public static void main(String[] args)        {                removeDir(new File("C:/webapps"));        }static void removeDir(File file)        {                File[] files = file.listFiles();                for(File f : files)                {                        if(f.isDirectory())                        {                                //如果是目录,递归                                removeDir(f);                        }                        else                                //如果是文件,则删除                                sopln(f.getAbsolutePath()+"..."+f.delete());                }                //每个文件夹 遍历完内部 已经是空文件夹了 现在可以把自己删了                sopln(file.getAbsolutePath()+"..."+file.delete());        }        static void sop(Object o)        {                System.out.print(o);        }        static void sopln(Object... o)        {                if(o.length==0)                        System.out.println();                else                        System.out.println(o[0]);        }}

—————————————————————————————
实例代码:建立一个目录中中Java文件的索引目录;结合集合。
—————————————————————————————

import java.io.*;import java.util.*;class Demo19_7{        public static void main(String[] args) throws IOException        {                //E:\\java                File f = new File("E:\\java");                List<File> filesList = new ArrayList<File>();                find(".java",f,filesList);               //将集合写入文件                writeList(new File(f,"listFile.txt"),filesList);        }        public static void find(String suffix, File dir, List<File> filesList) throws IOException        {                File[] files = dir.listFiles();                for(File f : files)                {                        if(f.isDirectory())                        {                                //递归的应用                                find(suffix,f,filesList);                        }else                        {                                //如果是以某后缀结尾就在集合中存入                                if(f.getName().toLowerCase().endsWith(suffix))                                        filesList.add(f);                        }                }        }        public static void writeList(File listFile,List<File> filesList) throws IOException        {                //目的:所以writer 或者 os                //纯文本 所以看 writer                //加速 所以 buffered                BufferedWriter bfw = new BufferedWriter(new FileWriter(listFile));                for(File f : filesList)                {                        bfw.write(f.getAbsolutePath());                        bfw.newLine();                        bfw.flush();                }                bfw.close();        }}

—————————————————————————————
—————————————————————————————
Properties
Properties是hashTable的子类,也就是说他具有map集合的特点,而且它里面存储的键值对都是字符串,是集合中和IO技术相结合的集合容器;
该对象的应用特点:
—可以用于键值对形式的配置文件;
—软件的基本的配置信息;
——软件的配置信息存储在一个配置文件中,每一次打开软件都加载该文件;
Properties可以操作硬盘文件上的键值对,通过load方法↓↓↓;
这里写图片描述
示例代码:
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(“file.config”);//file.config纯文本文件
/*
file.config中的内容格式(键值对):
aaa1=bbbb1
aaa2=bbbb2

*/
prop.load(fis);
//接下来就可以通过prop.getProperties(“键”)的形式获取值了,比如
prop.getProperties(“aaa1”)//得到bbb1
—————————————————————————————
实例代码:
—————————————————————————————

import java.util.*;import java.io.*;class Demo19_8{        public static void main(String[] args) throws IOException        {                Properties pro = new Properties();                pro.setProperty("zhangsan","30");                pro.setProperty("lisi","40");                sopln(pro.getProperty("lisi"));                //Set<String> stringPropertyNames()                                  //获取所有的键的set集合                Set<String> set = pro.stringPropertyNames();                for(String s : set)                {                        System.out.println(s+"____"+pro.getProperty(s));                }                                //对字符流和字节流均支持,store方法用来存储配置信息                pro.store(new FileOutputStream("info1.txt"),"comment1");                pro.store(new FileWriter("info2.txt"),"comment1");                        //store(OutputStream out, String comments)        }        static void sop(Object o)        {                System.out.print(o);        }        static void sopln(Object... o)        {                if(o.length==0)                        System.out.println();                else                        System.out.println(o[0]);        }}

—————————————————————————————
执行结果:
得到这两个文件:
这里写图片描述
—————————————————————————————
我们再来一个实例:
—记录应用程序运行次数,如果达到使用次数,给出购买完整版提示;
—————————————————————————————

import java.util.*;import java.io.*;class Demo19_9{        /*        记录应用程序运行次数,如果达到使用次数,给出注册提示        配置文件存于Demo19_9.config文件中        */        public static void main(String[] args) throws IOException        {                Properties pro = new Properties();                File f = new File("Demo19_9.config");                if(!f.exists())                {                        pro.setProperty("use.time","1");                        pro.store(new FileWriter("Demo19_9.config"),"使用次数统计");                        //pro.storeToXML(new FileOutputStream("Demo19_9.config"),"使用次数统计");                }                else                {                        //pro.load(new FileReader(f));                        pro.loadFromXML(new FileInputStream(f));                        int useCount = Integer.parseInt(pro.getProperty("use.time"));                        if(useCount>=5)                        {                                System.out.println("您好,您的使用次数已经达到极限,请购买完整版!");                                return;//结束程序                        }                        //使用次数加1                        useCount++;                        pro.setProperty("use.time",String.valueOf(useCount));                        pro.store(new FileWriter("Demo19_9.config"),null);                        //pro.storeToXML(new FileOutputStream("Demo19_9.config"),null);                }                System.out.println("程序已正常运行...!");        }}

—————————————————————————————
执行结果:5次打开后:
这里写图片描述
使用store方法得到的配置文件格式如下:
这里写图片描述
使用storeToXML方法得到的配置文件格式如下:
这里写图片描述
加载方式有两种,一种是load方法,一种是loadFromXML方法;XML格式的配置文件需要用loadFromXML加载,而不能用load:
—void load(InputStream inStream)
——从输入流中读取属性列表(键和元素对)。
—void load(Reader reader)
——按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
—void loadFromXML(InputStream in)
——将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中。
当然,根据代码我们把配置文件删除了,就又能够用5次了,当然真正的开发不会用这么简单的逻辑来进行验证的。
很多的应用都是以XML配置文件为主的,然而Java中能够让我们操作XML文件很麻烦,所以工具dom4j应运而生,大家可以自行去了解这款工具;
—————————————————————————————
—————————————————————————————
PrintWriter
前面的小节在将PrintStream的时候,也小小的涉及了一下这个流对象:
PrintWriter:
—提供了println打印方法,可以保证将这些数据的数据原样性打印出来:
我们看到其API方法中有很多重载的println方法:
这里写图片描述
更多的print方法大家可以去API查看,这里不再列出了。
其构造函数也非常有特点:
—PrintWriter构造函数可以接收的:
——①File对象 File
——②字符串路径 String
——③字符输出流Writer
—PrintStream构造函数可以接收的:
——①File对象 File
——②字符串路径 String
——③字节输出流OutputStream
——④字符输出流Writer
—这样一对比下来我们就发现区别了,PrintStream构造函数能接受输出流。
我们用一个实例代码对PrintWriter进行小结:
—————————————————————————————

import java.io.*;class Demo19_10{        public static void main(String[] args) throws IOException        {                //System.out.println("Hello World!");                BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));                PrintWriter pw = new PrintWriter(System.out,true);                //PrintWriter pw = new PrintWriter(new FileWriter("PrintWriter.txt"),true);                String line = null;                while((line = bfr.readLine())!=null)                {                        if("over".equals(line))                            return;                        pw.println(line.toUpperCase());//自动刷新,由于上面的true                }                pw.close();                bfr.close();        }}

—————————————————————————————
执行结果:键盘输入字母回车,以大写打印出来,输入over回车程序结束;
提醒:PrintWriter和PrintStream,能够自动刷新,还能够和转换流一样结合码表来使用:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
—————————————————————————————
—————————————————————————————
合并流
SequenceInputStream
两个构造方法:
—其中第一个会用到了枚举,枚举在Vector中得到
这里写图片描述
这就是我们在早期小结中讲道德Vector并没有完全被淘汰的原因;
实例代码:合并几个文件中的内容到一个中去;
—————————————————————————————

import java.io.*;import java.util.*;//要使用Vectorclass Demo19_11{        public static void main(String[] args) throws IOException        {                Vector<InputStream> v = new Vector<InputStream>();                v.add(new FileInputStream("info1.txt"));                v.add(new FileInputStream("info2.txt"));                //通过Vector得到枚举变量,这个枚举变量需要传给                //SequenceInputStream的构造方法                Enumeration<InputStream> en = v.elements();//得到的是枚举                //使用参数的枚举类的构造方法                SequenceInputStream sis = new SequenceInputStream(en);                //现在我们就可以把sis当成一个普通字节流来使用就好了                //我们需要一个最终整合的输出流,和文件                FileOutputStream fos = new FileOutputStream("info.txt");                //加多一层缓冲                BufferedOutputStream bfos = new BufferedOutputStream(fos);                byte[] buf = new byte[1024];                int len = 0;                while((len = sis.read(buf))!=-1)                {                        bfos.write(buf,0,len);                        bfos.flush();                }                bfos.close();                sis.close();        }}

—————————————————————————————
执行结果:
这里写图片描述
—————————————————————————————
SequenceInputStream的应用,对切割成几部分的文件进行合并,实例代码:
—————————————————————————————

import java.io.*;import java.util.*;//要使用Vectorclass Demo19_12{        /*SequenceInputStream的应用,对切割成几部分的文件进行合并*/        public static void main(String[] args) throws IOException        {                //splitFile(new File("halohoop - 天梯.mp3"));                mergeFiles(new File("halohoop - 天梯.mp3"));        }        static void splitFile(File file) throws IOException        {                //获取文件名字                String fileName = file.getName();                //首先获取一个文件的输入流                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));                //构建一个引用输出流的引用,加缓冲                BufferedOutputStream bos = null;                byte[] buf = new byte[1024*1024];//1mb大小的缓冲区                int len = 0;                int count = 0;//分块命名数量                while((len = bis.read(buf))!=-1)                {                        bos = new BufferedOutputStream(                                new FileOutputStream(fileName+".part"+(++count)));                        bos.write(buf,0,len);                        bos.flush();                        //由于一个bos实例只是一轮游,                        //因此循环一次关一次资源                        bos.close();                }                bis.close();        }        static void mergeFiles(File file) throws IOException        {                String fileName = file.getName();                int tmp = fileName.lastIndexOf(".");                String suffix = fileName.substring(tmp);                fileName = fileName.substring(0,tmp);                Vector<InputStream> v = new Vector<InputStream>();                v.add(new FileInputStream(fileName+suffix+".part1"));                v.add(new FileInputStream(fileName+suffix+".part2"));                v.add(new FileInputStream(fileName+suffix+".part3"));                v.add(new FileInputStream(fileName+suffix+".part4"));                v.add(new FileInputStream(fileName+suffix+".part5"));                //得到需要合并文件的枚举列表                Enumeration<InputStream> en = v.elements();                //构建合并流                SequenceInputStream sis = new SequenceInputStream(en);                //输入流加入缓冲                BufferedInputStream bis = new BufferedInputStream(sis);                //输出流加入缓冲                BufferedOutputStream bos                        = new BufferedOutputStream(new FileOutputStream(fileName+"_merge"+suffix));                byte[] buf = new byte[1024];                int len = 0;                //合并                while((len = bis.read(buf))!=-1)                {                        bos.write(buf,0,len);                }                bos.close();                bis.close();        }}

—————————————————————————————
执行结果:
splitFile方法执行结果:
这里写图片描述
mergeFiles方法执行结果:
这里写图片描述

0 0
原创粉丝点击