Java 递归调用和非递归调用

  领导要求我跑批量报文,但是文件夹下的文件按文件修改时间的先后顺序(升序) 一个一个将报文文件放到目录B中,camel会实时扫描解析B目录下的文件,解析完后会将该文件删除,因为报文的先后顺序对业务有影响,所以要求放入B目录下的报文一次只能放一个,等到B中扫描解析完将该报文文件删除后再放入另外一个报文,因为报文有上万个,手动放回很慢,所以我写了一个java小程序自动copy放入。

  

package com.message;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.io.FileUtils;

public class MessageTest {
    
    public static void main(String[] args) throws Exception{
        
        //String sPath = "E:/message_mm1/message_mm2/"; //源目录
        //String toPath = "E:/message_mm1/message_mm3/";//目标目录
        
        //linux 目录
        //String sPath = "/usr/local/mm_test/";//源目录
        //String toPath = "/usr/local/mm_test_20170418/";//目标目录
        String sPath = "/usr/local/message_mm/message_mm_20170416/";//源目录
        String toPath = "/usr/local/messageTest/mm/";//目标目录
        
        List<File> sourceList = getFileSort(sPath);
        System.out.println("源目录文件总数========="+sourceList.size());

        int sIndex = 0; //源目录文件列表开始下标
        loopCopy(sIndex,sPath, toPath,sourceList);
    }
    
    /**
     * do while循环的方式copy文件
     * @param sIndex 读取源目录文件的下标
     * @param sPath 源目录
     * @param toPath 目标目录
     * @param sourceList 源目录下文件组成的List
     */
    public static void loopCopy(int sIndex,String sPath, String toPath,List<File> sourceList){
        try {
            boolean flag = true;
            do{
                File toFile=new File(toPath);
                File[] toList = toFile.listFiles();
                if(toList.length==0){
                    if(sIndex < sourceList.size()){
                        FileUtils.copyFile(new File(sPath+sourceList.get(sIndex).getName()), new File(toPath+sourceList.get(sIndex).getName()));
                        System.out.println("拷贝成功,文件名:"+sourceList.get(sIndex).getName()+"文件最后修改时间:"+sourceList.get(sIndex).lastModified());
                        Thread.sleep(50); //休眠50ms
                        sIndex++;
                    }else{
                        System.out.println("执行结束,共拷贝文件总数="+sIndex);
                        flag = false;
                    }
                }else{
                    //目标目录文件未处理完,再休眠50ms
                    Thread.sleep(50); 
                }
                
            }while(flag);
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件拷贝异常,异常原因:"+e.getMessage());
        }
    }
    
    /**
     * 递归的方式copy文件
     * @param sIndex 读取源目录文件的下标
     * @param sPath 源目录
     * @param toPath 目标目录
     * @param sourceList 源目录下文件组成的list
     */
    public static void recursionCopy(int sIndex,String sPath, String toPath,List<File> sourceList){
        File toFile=new File(toPath);
        File[] toList = toFile.listFiles();
        //System.out.println("toList========="+toList);
        try {
            if(toList.length==0){
                if(sIndex < sourceList.size()){
                    FileUtils.copyFile(new File(sPath+sourceList.get(sIndex).getName()), new File(toPath+sourceList.get(sIndex).getName()));
                    System.out.println("拷贝成功,文件名:"+sourceList.get(sIndex).getName()+"文件最后修改时间:"+sourceList.get(sIndex).lastModified());
                    Thread.sleep(50); //休眠50ms
                    sIndex++;
                    recursionCopy(sIndex,sPath, toPath,sourceList);
                }else{
                    System.out.println("执行结束,共拷贝文件总数="+sIndex);
                    
                }
            }else{
                //目标目录文件未处理完,再休眠50ms
                Thread.sleep(50); 
                recursionCopy(sIndex,sPath, toPath,sourceList);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件拷贝异常,异常原因:"+e.getMessage());
        }
    }
    
    /**
     * 获取目录下所有文件(按时间升序排序)
     * 
     * @param path
     * @return
     */
    public static List<File> getFileSort(String path) {
 
        List<File> list = getFiles(path, new ArrayList<File>());
        if (list != null && list.size() > 0) {
            Collections.sort(list, new Comparator<File>() {
                public int compare(File file, File newFile) {
                    if (file.lastModified() > newFile.lastModified()) {
                        return 1;
                    } else if (file.lastModified() == newFile.lastModified()) {
                        return 0;
                    } else {
                        return -1;
                    }
 
                }
            });
 
        }
 
        return list;
    }
    
    /**
     * 
     * 获取目录下所有文件
     * 
     * @param realpath
     * @param files
     * @return
     */
    public static List<File> getFiles(String realpath, List<File> files) {
 
        File realFile = new File(realpath);
        if (realFile.isDirectory()) {
            File[] subfiles = realFile.listFiles();
            for (File file : subfiles) {
                if (file.isDirectory()) {
                    getFiles(file.getAbsolutePath(), files);
                } else {
                    files.add(file);
                }
            }
        }
        return files;
    }
}

上面的代码中第一次采用递归的方式调用,即方法recursionCopy,在copy了几百个文件后,抛出 StackOverflowError 异常【堆栈溢出】,因为每当Java程序启动一个新的线程时,java虚拟机会为他分配一个栈,java栈以帧为单位保持线程运行状态;当线程调用一个方法是,jvm压入一个新的栈帧到这个线程的栈中,只要这个方法还没返回,这个栈帧就存在。如果方法的嵌套调用层次太多(如递归调用),随着java栈中的帧的增多,最终导致这个线程的栈中的所有栈帧的大小的总和大于-Xss设置的值,而产生StackOverflowError溢出异常。 
  递归调用了recursionCopy次数太多导致栈溢出,递归调用虽然方法简单,但是容易发生StackOverflowError异常,所以比较安全一点的做法就是:用循环的方式代替递归调用防止栈溢出,loopCopy()方法中采用do...while方法代替递归,具体查看上面代码

原文地址:https://www.cnblogs.com/lyftest/p/6733787.html