zoukankan      html  css  js  c++  java
  • java基础之流的事例

    2.JAVA 遍历文件夹下的所有文件(递归调用和非递归调用)

    1、Java断点续传原理

    =====

    实战演练

    • FileInputStream类的使用:读取文件内容
    public class A1 {
    
        public static void main(String[] args) {
            A1 a1 = new A1();
            //电脑d盘中的abc.txt 文档
            String filePath = "D:/abc.txt" ;
            String reslut = a1.readFile( filePath ) ;
            System.out.println( reslut ); 
        }
    
        /**
         * 读取指定文件的内容
         * @param filePath : 文件的路径
         * @return  返回的结果
         */
        public String readFile( String filePath ){
            FileInputStream fis=null;
            String result = "" ;
            try {
                // 根据path路径实例化一个输入流的对象
                fis  = new FileInputStream( filePath );
    
                //2. 返回这个输入流中可以被读的剩下的bytes字节的估计值;
                int size =  fis.available() ;
                //3. 根据输入流中的字节数创建byte数组;
                byte[] array = new byte[size];
                //4.把数据读取到数组中;
                fis.read( array ) ; 
    
                //5.根据获取到的Byte数组新建一个字符串,然后输出;
                result = new String(array); 
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }catch (IOException e) {
                e.printStackTrace();
            }finally{
                if ( fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            return result ;
        }
    
    }
    
    • FileOutputStream 类的使用:将内容写入文件
    public class A2 {
    
        public static void main(String[] args) {
            A2 a2 = new A2();
            //电脑d盘中的abc.txt 文档
            String filePath = "D:/abc.txt" ;
            //要写入的内容
            String content = "今天是2017/1/9,天气很好" ;
            a2.writeFile( filePath , content  ) ;
        }
    
        /**
         * 根据文件路径创建输出流
         * @param filePath : 文件的路径
         * @param content : 需要写入的内容
         */
        public void writeFile( String filePath , String content ){
            FileOutputStream fos = null ;
            try {
                //1、根据文件路径创建输出流
                fos  = new FileOutputStream( filePath );
    
                //2、把string转换为byte数组;
                byte[] array = content.getBytes() ;
                //3、把byte数组输出;
                fos.write( array );
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }catch (IOException e) {
                e.printStackTrace();
            }finally{
                if ( fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    }
    
    

    注意:

    1. 在实际的项目中,所有的IO操作都应该放到子线程中操作,避免堵住主线程。
    2. FileInputStream在读取文件内容的时候,我们传入文件的路径("D:/abc.txt"), 如果这个路径下的文件不存在,那么在执行readFile()方法时会报FileNotFoundException异常。
    3. FileOutputStream在写入文件的时候,我们传入文件的路径("D:/abc.txt"), 如果这个路径下的文件不存在,那么在执行writeFile()方法时, 会默认给我们创建一个新的文件。还有重要的一点,不会报异常。

    效果图:

     
    这里写图片描述
    • 综合练习,实现复制文件,从D盘复制到E盘
    public class A3 {
    
        public static void main(String[] args) {
            A3 a2 = new A3();
    
            //电脑d盘中的cat.png 图片的路径
            String filePath1 = "D:/cat.png" ;
    
            //电脑e盘中的cat.png 图片的路径
            String filePath2 = "E:/cat.png" ;
    
            //复制文件
            a2.copyFile( filePath1 , filePath2 );
    
        }
    
        /**
         * 文件复制 
         * @param filePath_old : 需要复制文件的路径
         * @param filePath_new : 复制文件存放的路径
         */
        public void copyFile( String filePath_old  , String filePath_new){
            FileInputStream fis=null ;
            FileOutputStream fout = null ;
            try {
                // 根据path路径实例化一个输入流的对象
                fis  = new FileInputStream( filePath_old );
    
                //2. 返回这个输入流中可以被读的剩下的bytes字节的估计值;
                int size =  fis.available() ;
                //3. 根据输入流中的字节数创建byte数组;
                byte[] array = new byte[size];
                //4.把数据读取到数组中;
                fis.read( array ) ; 
    
                //5、根据文件路径创建输出流
                fout = new FileOutputStream( filePath_new ) ;
    
                //5、把byte数组输出;
                fout.write( array );
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }catch (IOException e) {
                e.printStackTrace();
            }finally{
                if ( fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if ( fout != null ) {
                    try {
                        fout.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }   
                }
            }
        }
    }
     

    2.JAVA 遍历文件夹下的所有文件(递归调用和非递归调用)

    1.不使用递归的方法调用.

    public void traverseFolder1(String path) {
            int fileNum = 0, folderNum = 0;
            File file = new File(path);
            if (file.exists()) {
                LinkedList<File> list = new LinkedList<File>();
                File[] files = file.listFiles();
                for (File file2 : files) {
                    if (file2.isDirectory()) {
                        System.out.println("文件夹:" + file2.getAbsolutePath());
                        list.add(file2);
                        foldeNum++;
                    } else {
                        System.out.println("文件:" + file2.getAbsolutePath());
                        fileNum++;
                    }
                }
                File temp_file;
                while (!list.isEmpty()) {
                    temp_file = list.removeFirst();
                    files = temp_file.listFiles();
                    for (File file2 : files) {
                        if (file2.isDirectory()) {
                            System.out.println("文件夹:" + file2.getAbsolutePath());
                            list.add(file2);
                            folderNum++;
                        } else {
                            System.out.println("文件:" + file2.getAbsolutePath());
                            fileNum++;
                        }
                    }
                }
            } else {
                System.out.println("文件不存在!");
            }
            System.out.println("文件夹共有:" + folderNum + ",文件共有:" + fileNum);
    
        }

    2.使用递归的方法调用.

    public void traverseFolder2(String path) {
    
            File file = new File(path);
            if (file.exists()) {
                File[] files = file.listFiles();
                if (null == files || files.length == 0) {
                    System.out.println("文件夹是空的!");
                    return;
                } else {
                    for (File file2 : files) {
                        if (file2.isDirectory()) {
                            System.out.println("文件夹:" + file2.getAbsolutePath());
                            traverseFolder2(file2.getAbsolutePath());
                        } else {
                            System.out.println("文件:" + file2.getAbsolutePath());
                        }
                    }
                }
            } else {
                System.out.println("文件不存在!");
            }
        }
    public static List<File> getFileList(String strPath) {
            File dir = new File(strPath);
            File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组
            if (files != null) {
                for (int i = 0; i < files.length; i++) {
                    String fileName = files[i].getName();
                    if (files[i].isDirectory()) { // 判断是文件还是文件夹
                        getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径
                    } else if (fileName.endsWith("avi")) { // 判断文件名是否以.avi结尾
                        String strFileName = files[i].getAbsolutePath();
                        System.out.println("---" + strFileName);
                        filelist.add(files[i]);
                    } else {
                        continue;
                    }
                }
    
            }
            return filelist;
        }

     2、Java断点续传原理

     为什么要使用断点续传

    在进行数据上传的时候可能是多线程操作,很多图像数据同时做上传或者单一的图像,如果图像比较多或者单一图像数据比较大,自然不希望失败一次或者暂停一次之后完全重传,有断点续传功能可以节省网络流量和节省用户时间,体验自然比你一次次的重传好很多。

     Java断点续传原理

    3.1什么是断点续传

    所谓断点续传,也就是要从文件已经下载的地方开始继续下载。在以前版本的 HTTP 协议是不支持断点的,HTTP/1.1 开始就支持了。

    一般断点下载时才用到 Range (请求报文)和 Content-Range(响应报文) 实体头。下面会介绍HTTP版本的发展历程。

    3.2什么是Range? 

    模拟http请求

    当用户在听一首歌的时候,如果听到一半(网络下载了一半),网络断掉了,用户需要继续听的时候,文件服务器不支持断点的话,则用户需要重新下载这个文件。而Range支持的话,客户端应该记录了之前已经读取的文件范围,网络恢复之后,则向服务器发送读取剩余Range的请求,服务端只需要发送客户端请求的那部分内容,而不用整个文件发送回客户端,以此节省网络带宽。

    3.3HTTP1.1规范的Range是怎样一个约定?

    如果Server支持Range,首先就要告诉客户端,咱支持Range,之后客户端才可能发起带Range的请求。这里套用唐僧的一句话,你不说我怎么知道呢。response.setHeader('Accept-Ranges', 'bytes');

    Server通过请求头中的Range: bytes=0-xxx来判断是否是做Range请求,如果这个值存在而且有效,则只发回请求的那部分文件内容,响应的状态码变成206,表示Partial Content,并设置Content-Range。如果无效,则返回416状态码,表明Request Range Not Satisfiable。如果不包含Range的请求头,则继续通过常规的方式响应。

    3.4应用场景

    假设你要开发一个多线程下载工具,你会自然的想到把文件分割成多个部分,比如4个部分,然后创建4个线程,每个线程负责下载一个部分,如果文件大小为403个byte,那么你的分割方式可以为:0-99 (前100个字节),100-199(第二个100字节),200-299(第三个100字节),300-402(最后103个字节)。

    分割完成,每个线程都明白自己的任务,比如线程3的任务是负责下载200-299这部分文件,现在的问题是:线程3发送一个什么样的请求报文,才能够保证只请求文件的200-299字节,而不会干扰其他线程的任务。这时,我们可以使用HTTP1.1的Range头。

    Range头域可以请求实体的一个或者多个子范围,Range的值为0表示第一个字节,也就是Range计算字节数是从0开始的:

    表示头500个字节:Range: bytes=0-499
    表示第二个500字节:Range: bytes=500-999 
    表示最后500个字节:Range: bytes=-500 
    表示500字节以后的范围:Range: bytes=500- 
    第一个和最后一个字节:Range: bytes=0-0,-1
    同时指定几个范围:Range: bytes=500-600,601-999  
    

    所以,线程3发送的请求报文必须有这一行:

    Range: bytes=200-299
    

    服务器接收到线程3的请求报文,发现这是一个带有Range头的GET请求,如果一切正常,服务器的响应报文会有下面这行:
    HTTP/1.1 206 OK

    表示处理请求成功,响应报文还有这一行
    Content-Range: bytes 200-299/403
    斜杠后面的403表示文件的大小

    3.5Http协议的发展历程

    HTTP协议到现在为止总共经历了3个版本的演化,第一个HTTP协议诞生于1989年3月。

    xml属性描述
    HTTP/0.9 1991年
    HTTP/1.0 1992-1996年
    HTTP/1.1 1997-1999年
    HTTP/2.0 2012-2014年

    也就是HTTP/1.1 从1997-1999 年就应用了,所以现在基本上是支持断点续传的。  

  • 相关阅读:
    docker怎么修改之前run时的env
    yum安装mysql
    springboot服务的Dockerfile
    openssh升级到8.4
    rpm与yum执行无反应
    ubuntn离线安装docker-ce
    centos7部署docker
    解决5版本的elasticsearch-head连接6版本的elasticsearch查询不到数据问题
    docker搭建elasticsearch:7.6.2并开启x-pack
    原生js 实现图片的拖拽缩放
  • 原文地址:https://www.cnblogs.com/awkflf11/p/12578242.html
Copyright © 2011-2022 走看看