Too主要是想实践一下Java的Comparator的用法。


我有一个文件夹,里面包含了100多个sql脚本文件,每个文件都是以update-x.x.x.x.sql的形式命名的,其中x.x.x.x为纯数字版本号。我想将这些SQL文件中的内容收尾相连复制到一个文件中(windows7下cmd终端上允许8k多字符的单行命令,嘘~幸亏没超过)。


分析:

1. 获取文件名

由于需要拼接的文件太多,决定写一段程序从指定文件夹中读出所有需要拼接在一起的文件的文件名并将获得的文件名用+号连接起来。

2. 文件名排序

虽然可以很容易获得一个文件夹下的所有文件的文件名,但困难的是如何对这些获取到的文件名进行排序。而且,排序的依据是每个文件名中包含的x.x.x.x版本信息。每个x为正整数集中的一个数字。问题又来了,在Java中,默认的字符串比较运算得出的结果是1.0.0.1, 1.0.0.10, 1.0.0.11, 1.0.0.2 ...看到问题了吧,这种排序方法显然不是数值自然排序法(即便使用Collections.sort()排出来的结果也是不正确的,必须要自己实现比较和排序方法)。

copy /A file1+file2+...+fileN ALLin1.sql

3. 剪贴板保存拼接好的命令行

将拼接好的命令放入剪贴板,这样我就可以直接将拼好的命令粘贴到cmd终端并执行。(当然有朋友肯定要说Java也能直接调Shell。是的,为了懒省事,我没有通过java来执行cmd命令。)


方案:

利用Netbeans写出程序读取文件名,并对其进行排序。然后拼接成命令行,在cmd终端中执行。


 
  

关键点:

1. file1+file2+...+fileN的copy命令参数需要准备。但由于需要拼接的文件太多(100多个文件)手工准备这些参数不可行。


代码:

public class NewEmptyJUnitTest1 implements ClipboardOwner {
    public NewEmptyJUnitTest1() {
    }
    @BeforeClass
    public static void setUpClass() {
    }
    @AfterClass
    public static void tearDownClass() {
    }
    @Before
    public void setUp() {
    }
    @After
    public void tearDown() {
    }
    @Test
    public void concatenateFileNamesInNameOrder() {
        StringBuilder sb = new StringBuilder("copy /A /Y ");
        List<String> fileNames = new ArrayList<>();
        File[] files;
        File dir = new File("C:\\Workspace\\Projects\\DB\\sql\\allinone");
        files = dir.listFiles();
        for (File file : files) {
            fileNames.add(file.getName());
        }
        Collections.sort(fileNames, new FileNameComparator());
        int count = 0;
        for (String filename : fileNames) {
            sb.append(filename).append("+");
            count++;
        }
        sb.deleteCharAt(sb.lastIndexOf("+"));
        sb.append(" ALLin1.sql");
          
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        StringSelection ss = new StringSelection(sb.toString());
        clipboard.setContents(ss, NewEmptyJUnitTest1.this);
          
        System.out.println("Total files: " + count);
        System.out.println(sb.toString());
    }
    @Override
    public void lostOwnership(Clipboard clipboard, Transferable contents) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
      
    private class FileNameComparator implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            int result = 0;
            int[] ver1 = getVersionFields(o1);
            int[] ver2 = getVersionFields(o2);
            for (int i = 0; i < 4; i++) {
                result = ver1[i] - ver2[i];
                if (result == 0) {
                    continue;
                } else {
                    return result;
                }
            }
            return 0;
        }
          
        private int[] getVersionFields(String str) {
            String pattern = "\\D*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\D*";  //0.0.0.0
            String versionStr = str.replaceAll(pattern, "$1");
            String[] verFields = versionStr.split("\\.");
              
            int[] versionFields = new int[4];
            Arrays.fill(versionFields, 0, 3, 0);
            int count = 0;
            for (String numStr : verFields) {
                versionFields[count] = Integer.parseInt(numStr);
                count++;
            }
            return versionFields;
        }
    }
}