021.6 IO流 练习

#######################################################################################
获取指定目录下所有的.java文件(包含子目录中的),并将这些java文件的绝路路径写入到一个文件中。建立一个java文件清单列表。
/*
 * 思路:
 * 1,一看到包含子目录,必须递归。
 * 2,写数据到文件,输出流。
 * 3,继续分析,发现只要.java ,需要过滤器。
 * 4,满足过滤的条件的文件有可能非常多,先进行存储。
 */

public class Test5 {
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        //被遍历的目录。
        File dir = new File("F:\\eclipse_javaCode");
        
        //明确一个过滤器。
        FileFilter filter = new FileFilterByEnding(".java");
        
        //符合过滤器条件的文件有很多,最好先存储起来,然后在进行操作。
        List<File> list = new ArrayList<File>();
        //获取指定文件清单。
        getFileList(dir,filter,list);
//        System.out.println(list.size());
        
        File destFile = new File(dir,"javalist.txt");
        write2File(list,destFile);
    }

    /**
     * 将集合中的数据的绝对路径写入到文件中。
     * @param list
     * @param destFile
     * @throws IOException 
     */
    public static void write2File(List<File> list, File destFile) throws IOException {
        FileOutputStream fos = null;
        BufferedOutputStream bufos = null;
        try{
            fos = new FileOutputStream(destFile);
            bufos = new BufferedOutputStream(fos);
            
            for(File file : list){
                String info = file.getAbsolutePath()+LINE_SEPARATOR;
                bufos.write(info.getBytes());
                bufos.flush();//每写一个绝对路径就刷新一次。
            }
        }finally{
            if(bufos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException("关闭失败");
                }
            }
        }
        
    }

    /**
     * 根据指定的过滤器在指定目录下获取所有的符合过滤条件的文件,并存储到list集合中。
     * @param dir
     * @param filter
     * @param list
     */
    public static void getFileList(File dir,FileFilter filter,List<File> list) {
        
        File[] files = dir.listFiles();
        
        for(File file : files){
            
            if(file.isDirectory()){
                getFileList(file,filter,list);
            }else{
                //如果是文件,传递到过滤器中去过滤。将满足条件存储起来。
                if(filter.accept(file)){
                    list.add(file);
                }
            }
        }
    }
}
includeMain.java
public class FileFilterByEnding implements FileFilter
{
    private String end;
    
    public FileFilterByEnding(String end) {
        super();
        this.end = end;
    }

    @Override
    public boolean accept(File pathname)
    {
        return pathname.getName().endsWith(end);
    }
}
FileFilterByEnding.java

//文本过滤器的使用
1)类的创建,继承File Filter,实现accept方法
2)对象使用,通过该类的accept方法,参数是File,比如filter.accept(file),查看FileFilter接口的原代码就可以发现就是要覆盖accept方法

##########################################################################################

作业:键盘录入多名学生的信息:格式:姓名,数学成绩,语文成绩,英文成绩
按总分由高到低,将学生信息进行排列到文件中

思路:
1、使用键盘录入技术
2、操作的学生信息,信息很多,将学生封装成对象
3、总分由高到低,将学生对象进行容器存储,使用TreeSet集合
4、将容器中 学生对象的信息写入到文件中

public class GetInfoTool
{
    //获取学生集合
    public static Set<Student> getStudent() throws NumberFormatException, IOException{
        return getStudent(null);
    }
    
    public static Set<Student> getStudent(Comparator<Student> comp) throws NumberFormatException, IOException{
        //1,键盘输入
        BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
        //创建存储学生的集合
        Set<Student> set = null;
        if(comp!=null){
            set = new TreeSet<Student>(comp);
        }else{
            set = new TreeSet<Student>();
        }
        
        //2,获取键盘录入的信息
        String line = null;
        while((line = bufr.readLine())!=null){
            
            if("over".equals(line)){
                break;
            }
            
            //因为录入的数据是有规律的,通过制定的规划进行分割
            String[] strs = line.split(",");
            //将数组中的元素封装成对象
            Student stu = new Student(Integer.parseInt(strs[0]), strs[1], 
                    Double.parseDouble(strs[2]), 
                    Double.parseDouble(strs[3]));
            //将学生存到集合中
            set.add(stu);
        }
        //这里的流是系统标准输入流——键盘,一旦关了,后面就用不到了
        
        return set;
    }
    
    public static void write2file(Set<Student> set, File file) throws IOException
    {
        BufferedWriter bufw = null;
        try{
            bufw = new BufferedWriter(new FileWriter(file));
            
            //遍历集合
            for(Student stu:set){
                bufw.write(stu.getName()+"\t"+stu.getEnglish());
                bufw.newLine();
                bufw.flush();
            }
        }finally{
            if(bufw!=null){
                bufw.close();
            }
        }
    }
}
GetInfoTool.java
public class Student implements Comparable<Student>
{
    private int num;
    private String name;
    private double math, english;
    private double sum;
    @Override
    public int compareTo(Student o)
    {
        double sub = this.sum - o.sum;
        return 0==sub?this.name.compareTo(o.name):(int)sub;
    }
    //...其他函数都是通过源码生成,不在重复
}
Student.java
public static void main(String[] args) throws NumberFormatException, IOException
{
    //创建逆向的比较器
    Comparator<Student>comp =  Collections.reverseOrder();
    
    //使用操作学生信息的工具类
    Set<Student> set = GetInfoTool.getStudent(comp);
    
    File file = new File("Student.txt");
    GetInfoTool.write2file(set, file);
}
Main.java

 

 

################################################################################################

read方法实现缓冲区和readLine方法,个人不建议仔细阅读这个代码。

/**
 * 自定义一个字符流缓冲区。 用于缓冲字符数据,从而提高操作效率。 
 * 并提供了更多操作缓冲区数据的方法。 需要使用具体的流对象来完成数据的获取。
 * 
 * 分析: 缓冲区应该具备什么? 1,必须要有数组。 2,需要对数组进行操作,对数组操作一定要有角标。
 * 
 * @author Teaching
 * 
 */
public class MyBufferedReader {
    private Reader r;
    // 定义一个字符数组,作为缓冲区。
    private char[] buf = new char[1024];
    // 定义了一个索引,用于操作数组中的元素。
    private int index = 0;
    // 定义了一个变量,用于记录读取字符的个数。
    private int count = 0;
    // 需要一初始化就具备一个流对象。
    public MyBufferedReader(Reader r) {// 可以对Reader的所有子类进行高效读取。
        this.r = r;
    }
    /**
     * 提供一个可以从缓冲区中读取一个字符的方法。
     * 高效方法。
     * @throws IOException 
     * 
     */
    public int read() throws IOException {
        /*
         * 1,需要先通过流对象从底层设备上获取一定数据的数据到缓冲区数组中。 使用流对象read(char[]);
         */
        //如果count记录字符个数的变量为0,说明缓冲区已经没有字符数据。
        if(count==0){
            //需要从设备上获取一定数量的数据存储到缓冲区中,并用count记录存储字符的个数。
            count = r.read(buf);
            //每取一次新的数据,就需要将角标归0.
            index = 0;
        }
        //如果count小于0,说明到-1,没有数据了,程序直接返回-1.
        if(count<0){
            return -1;
        }
        //从缓冲区中取出一个字符。
        char ch = buf[index];
        //角标自增。
        index ++;
        //计数器要自减。
        count --;
        return ch;
    }
    /**
     *  基于高效的read方法,建立一个一次可以读取一行的数据的方法。
     *  将行终止符前的数据转成字符串返回。
     * @return
     * @throws IOException 
     */
    public String readLine() throws IOException{
        /*
         * 思路;
         * 
         * 从缓冲区中一次获取一个字符,并将这个字符存储到临时容器中。
         * 每获取一个字符都要进行判断,只要不是行终止符都进行存储。
         * 一旦读取到行终止符,就将临时容器中的数据转成字符串返回。
         * 
         */
        //1,定义一个临时容器。
        StringBuilder sb = new StringBuilder();
        //2,调用本类中的read方法,从缓冲区中读取一个字符,存储到临时容器中。
        //存的时候要注意:必须判断,如果是行终止符就不要存储了。就将临时容器中的
        //字符转成字符串返回。
        int ch = 0;
        while((ch=this.read())!=-1){
            if(ch=='\r'){
                continue;
            }
            if(ch=='\n'){
                return sb.toString();
            }
            sb.append((char)ch);//将读取到的字符数字转成char类型,存储到sb中。
        }
        //万一文本中最后以后没有行终止符,判断一下sb中是否有内容,如果有则返回。
        if(sb.length()!=0){
            return sb.toString();
        }
        return null;
    }
    // 关闭流资源。
    public void close() throws IOException {
        // 其实内部就是关闭具体的流。
        r.close();
    }
}
View Code

 

posted @ 2018-05-06 20:55  Alos403  阅读(274)  评论(0编辑  收藏  举报