领导要求我跑批量报文,但是文件夹下的文件按文件修改时间的先后顺序(升序) 一个一个将报文文件放到目录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方法代替递归,具体查看上面代码