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()排出来的结果也是不正确的,必须要自己实现比较和排序方法)。

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

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

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

方案:

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

1
 

关键点:

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

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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;
        
}
    
}
}