zoukankan      html  css  js  c++  java
  • Day13:IO流

    IO流主要涉及到Java中的数据是怎样传送的,是一什么方式传送的,又是以什么方式阅读的

    IO流:
        IO:用于处理设备上的数据的技术。设备:内存,硬盘,光盘。
        流:系统资源,windows系统本身就可以操作设备。各种语言只是使用系统平台上的这个资源。
            并对外提供了各种语言自己的操作功能,这些功能最终调用的是系统资源。
            使用完资源一定要记住:释放。
            
    IO:java中所涉及的功能对象都存储到java.io包中。    
    设备上数据最常见的存储表现形式文件file.
    小知识点
    * 递归:函数自身调用自身。函数内部又使用到了该函数功能。
    * 什么时候使用?
    * 功能被重复使用,但是每次该功能使用参与运算的数据不同时,可以考虑递归方式解决。
    * 使用时,一定要定义条件。
    * 注意递归次数过多,会出现栈内存溢出。
    * String LINE_SEPARATOR = System.getProperty("line.separator");(任何系统都可以的换行符)
    /*
     * 将数据写入到文件中。
     * 使用字节输出流。
     * FileOutputStream。
     */
    File dir = new File("tempfile");
    if(!dir.exists()){
        dir.mkdir();
    }
    //1,创建字节输出流对象。用于操作文件,在对象初始化时,必须明确数据存储的目的地。
    //输出流所关联的目的地,如果不存在,会自动创建。如果存在,则覆盖。
    FileOutputStream fos = new FileOutputStream("tempfile\fos.txt");
            
    //2,调用输出流的写功能。
    fos.write("abcde".getBytes());
                    
    //3,释放资源。
    fos.close();
        public static void main(String[] args) {
    
       //         需求获取一个想要的指定文件的集合。获取javase_code下(包含子目录)的所有的.java的文件对象。并存储到集合中。
            /*
             * 思路:
             * 1,既然包含子目录,就需要递归。
             * 2,在递归过程中需要过滤器。
             * 3,满足条件,都添加到集合中。
             */ 
            File dir = new File("e:\javase_code");
            
            List<File> list = fileList(dir,".java");
            
            for(File file : list){
                System.out.println(file);
            }   
        }
        /**
         * 对指定目录进行递归。
         * 
         * 多级目录下都要用到相同的集合和过滤器。那么不要在递归方法中定义,而是不断的进行传递。
         * 
         * @param dir 需要遍历的目录。
         * @param list 用于存储符合条件的File对象。
         * @param filter 接收指定的过滤器。
         */
        public static void getFileList(File  dir,List<File> list,FileFilter filter){
     
            //1,通过listFiles方法,获取dir当前下的所有的文件和文件夹对象。
            File[] files = dir.listFiles();
            
            //2,遍历该数组。
            for(File file : files){
                
                //3,判断是否是文件夹。如果是,递归。如果不是,那就是文件,就需要对文件进行过滤。
                if(file.isDirectory()){
                    getFileList(file, list, filter);
                }else{
                    //4,通过过滤器对文件进行过滤
                    if(filter.accept(file)){
                        list.add(file);
                    }
                }
                
            }
        }

      
       /**
         * 定义一个获取指定过滤器条件的文件的集合。
         */
        public static List<File> fileList(File dir,String suffix){
            
            //1,定义集合。
            List<File> list = new ArrayList<File>();
            
            //2,定义过滤器。
            FileFilter filter = new FileFilterBySuffix(suffix);//自定义的文件拦截器
            
            getFileList(dir, list, filter);
            
            return list;  
        }
    File:IO技术用于操作设备上数据的,而数据最常见的体现方式是文件。
    先了解了文件的操作。
        创建,删除,存在,隐藏,获取......;
    
    
    需求:怎么操作文件的数据呢?
        使用IO流对象。而且文件数据都是字节存在。
    学习了可以操作文件的字节流。    
        InputStream
            |--FileInputStream
        OutputStream
            |--FileOutputStream
            
    为了提高了操作效率。引入缓冲区。
        InputStream
            |--FileInputStream
            |--FilterInputStream
                |--BufferedInputStream
        OutputStream
            |--FileOutputStream
            |--FilterOutputStream    
                |--BufferedOutputStream
    
    发现,文件数据,媒体文件字节流没问题。
    但是对于文本文件,想要操作文件中的中文数据时,字节流只能操作字节,需要我们字节解码成字符。麻烦。
    所以就到API找对象,就发现字符流中有字节和字符的桥梁,传说中的转换流。
        Reader
            |--InputStreamReader:字节-->字符。
        Writer
            |--OutputStreamWriter:字符--->字节。
            
    它们出现了解决了中文的编码转换问题。
    
    为了便捷操作字符文件。找到了转换流的子类,但是它有局限性,只能操作文件,而且是默认编码。
    如果不操作文件,而且编码不是默认的,需要使用转换流。
        Reader
            |--InputStreamReader:字节-->字符。
                |--FileReader
        Writer
            |--OutputStreamWriter:字符--->字节。
                |--FileWriter
    
        
    为了提高了字符流的操作效率。引入字符串的缓冲区。
    字符流=字节流+编码
    Reader
    |--InputStreamReader:字节-->字符。 |--FileReader=FileInputStream+InputStreamReader |--BufferedReader:String readLine() Writer |--OutputStreamWriter:字符--->字节。 |--FileWriter=FileOutputStream+OutputStreamWritter |--BufferedWriter:String newLine();

            /*
             * 需求:把目录中的1.jpg复制一次并把文件名改为2.jpg
             */
            //1、获取文件
            File file = new File("1.jpg");
            //2、创建具体流对象,明确数据源
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
            //3、创建对冲流,明确目的文件
            FileOutputStream fos = new FileOutputStream("2.jpg");
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            //4、进行频繁读写
            int len = 0;
            byte[] buf = new byte[1024];
            while((len=bis.read(buf))!=-1){
                //写入流
                bos.write(buf,0,len);
                //刷新流
                bos.flush();
            }
            //5、释放资源
            fis.close();
            fos.close();

    接着,来一个综合性的流的练习题

            /*
             * 作业:键盘录入多名学生的信息:格式:姓名,数学成绩,语文成绩,英文成绩.
             * 按总分由高到低,将学生的信息进行排列到文件中。
             * 
             * 思路:
             * 1,使用键盘录入技术。
             * 2,操作的学生信息,信息很多,需要将信息封装成学生对象。
             * 3,总分由高到低,需要排序,需要对学生对象中的总分排序。需要将多个学生对象进行容器存储。
             * 哪个容器呢?TreeSet集合。
             * 4,将容器中学生对象的信息写入到文件中。
             * 
             * 
             */
            
            
            //创建一个逆序的比较器。
            Comparator<Student> comp = Collections.reverseOrder();
            
            //使用操作学生信息的工具类。
            Set<Student> set = GetInfoTool.getStudents(comp);
            
            File destFile = new File("tempfile\info.txt");
            GetInfoTool.write2File(set, destFile);
    //学生类
    public
    class Student implements Comparable<Student> { private String name; private int ma,cn,en; private int sum; public Student() { super(); } public Student(String name, int ma, int cn, int en) { super(); this.name = name; this.ma = ma; this.cn = cn; this.en = en; this.sum = ma+cn+en; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + sum; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (sum != other.sum) return false; return true; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getMa() { return ma; } public void setMa(int ma) { this.ma = ma; } public int getCn() { return cn; } public void setCn(int cn) { this.cn = cn; } public int getEn() { return en; } public void setEn(int en) { this.en = en; } public int getSum() { return sum; } public void setSum(int sum) { this.sum = sum; } @Override public int compareTo(Student o) { int temp = this.sum - o.sum; return temp==0?this.name.compareTo(o.name):temp; } }
    //对学生信息进行操作
    public
    class GetInfoTool { /** * 获取所有学生对象集合,按照学生对象的自然排序。 * @throws IOException */ public static Set<Student> getStudents() throws IOException{ return getStudents(null); } /** * 获取学生对象集合,按照指定的比较器排序。 * @param comp * @return * @throws IOException */ public static Set<Student> getStudents(Comparator<Student> comp) throws 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(strs[0],Integer.parseInt(strs[1]) ,Integer.parseInt(strs[2]) ,Integer.parseInt(strs[3])); //将学生对象存储到集合中。 set.add(stu); } //关闭键盘录入须知:如果后面不在使用键盘录入是可以关闭的,如果后面还要使用,就不要关闭,继续通过System.in就可以获取。 // bufr.close(); return set; } /** * 将集合中的学生信息写入到文件中。 * @throws IOException */ public static void write2File(Set<Student> set,File destFile) throws IOException{ BufferedWriter bufw = null; try{ bufw = new BufferedWriter(new FileWriter(destFile)); //遍历集合。 for(Student stu : set){ bufw.write(stu.getName()+" "+stu.getSum()); bufw.newLine(); bufw.flush(); } }finally{ if(bufw!=null){ try { bufw.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
    缓冲区原理:
        临时存储数据的方法。减少对设备操作的频率,提高了效率。其实就是将数据临时缓存到了内存(数组)中。
        
    模拟一个BufferedReader。
        
        
    Writer
        |--TextWriter
        |--MediaWriter
    
    在对数据写入操作过程中,希望提升效率。
    要对操作文本的对象提升效率,使用缓冲区技术。
    
    Writer
        |--TextWriter
            |--BufferedTextWriter
        |--MediaWriter    
            |--BufferedMediaWirter
        |--AudioWriter
            |--BufferedAudioWriter
            
    这样的体系,为了增加一些功能,而通过产生子类来完成,会导致继承体系变得很臃肿。
    重新思考体系的设计问题。都是在写的方法进行效率的提升。
    为什么不将该功能进行单独的封装呢?要提升哪个具体对象,将哪个具体对象交给该功能不就可以了吗?
    
    class BufferedWriter extends Writer
    {
        BufferedWriter(Writer w)
        {
        }
        /*
        BufferedWriter(TextWriter w)
        {}
        
        BufferedWriter(MediaWriter w)
        {
        }
        */
    }        
    Writer
        |--TextWriter
        |--MediaWriter
        |--AudioWriter
        |--BufferedWriter
            
    TextWriter tw = new TextWriter();
    BufferedWriter bufw = new BufferedWriter(tw);
    //tw.write();
    bufw.write();
        
    解决:可以给对象提供额外的功能(职责)。比继承这种方式更为灵活。
    起个名字,装饰设计模式(Wrapper,Decorator)。
    装饰类与被装饰类都所属于同一个体系。
    同时装饰类中持有被装饰类的引用。
  • 相关阅读:
    案例分享:只因在 update 语句中误用一个双引号,生产数据竟然都变成了 0
    快速了解Service Mesh微服务架构实现服务间gRPC通信
    实战|如何优雅地自定义Prometheus监控指标
    微服务架构中如何快速构建一个数据报告服务?
    k8s微服务接入SkyWalking,三分钟教你怎么玩!
    Python基础-27-面向对象
    Python基础-21-字典
    Jmeter JSON提取器
    Jmeter正则表达式提取器
    访问github,修改host文件
  • 原文地址:https://www.cnblogs.com/vijay/p/3508066.html
Copyright © 2011-2022 走看看