使用java API一定要注意javadoc里面关于API的描述,不是所有的API behaviour都在任意平台一致的


系统中使用了java file的rename方法,相关的测试用例一直在linux平台工作的很好,可是当我把代码checkout到windows的时候发现测试失败了,仔细研究了代码,发现系统有多线程使用同一个文件,一个线程是通过系统的java 类往文件做读写操作,另外一个线程在达到某种条件的时候()比如文件大小限制)调用rename方法移动文件。我第一感觉认为这种代码不可能不出错,rename的时候会丢失数据,可是实际linux的测试结果一切都好,只有我在windows的测试才出了问题。我自己简化创建了以下的代码来测试rename在windows和linux的不同,同时也在javadoc看到了相关的描述,这个函数是平台相关的实现。

在开发的时候一定要注意api是否是平台相关的,否则会发现很多稀奇古怪的问题。


 import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
 
public class Test {
    /**
     * @param args
     */
    public static void main(String[] args) {
        new Thread(new Runnable(){
            @Override
            public void run() {
                // TODO Auto-generated method stub
                File file = new File("temp");
                try {
                    file.createNewFile();
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                
                                
                try {
                    RandomAccessFile raf = new RandomAccessFile(file,"rw");
                    while(true){
                        raf.seek(file.length());
                        raf.write(13);
                    }
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
            }
            
        }).start();
        
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        
        new Thread(new Runnable(){
            @Override
            public void run() {
                File file = new File("temp");
                //System.out.println(file.getAbsolutePath());
                moveFile(file);
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                System.out.println(file.getAbsolutePath());
                
                
            }
            private void moveFile(File file) {
                System.out.println(file.renameTo(new File("temp2")));
                System.out.println(file.getAbsolutePath());
            }
            
            
            
            
        }).start();
    }
}



Windows结果
false
C:\Users\elulian\Documents\cloudlu\CGC_BUSS\Projects\ECE\LocalCDR\workspace\Test\temp
C:\Users\elulian\Documents\cloudlu\CGC_BUSS\Projects\ECE\LocalCDR\workspace\Test\temp
temp2创建失败,同时temp文件的size不再增加

Linux结果 
true
C:\Users\elulian\Documents\cloudlu\CGC_BUSS\Projects\ECE\LocalCDR\workspace\Test\temp
C:\Users\elulian\Documents\cloudlu\CGC_BUSS\Projects\ECE\LocalCDR\workspace\Test\temp
temp2创建成功,但是temp文件的size也不再增加 

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;



public class Test {

    
    public static int count = 0;
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        new Thread(new Runnable(){

           
            @Override
            public void run() {
                // TODO Auto-generated method stub
                
                
                while (true) {
                    File file = new File("temp");
                    
                                    
                    try {
                        RandomAccessFile raf = new RandomAccessFile(file,"rw");
                        raf.seek(file.length());
                        for (int i=0; i<256; i++)
                            raf.write(i);
                        raf.close();
                        count++;
                        
                    } catch (FileNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (Exception e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    } catch (Throwable e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                }
            }
            
        }).start();
        
        
        
        new Thread(new Runnable(){

            @Override
            public void run() {
                
                int i = 0;
                
                while(true){
                
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                
                File file = new File("temp");
                //System.out.println(file.getAbsolutePath());
                moveFile(file, ("temp" + i));
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                //System.out.println(file.getAbsolutePath());
                i++;
                }
                
            }

            private void moveFile(File file, String newFile) {
                System.out.println(count);
                System.out.println(file.renameTo(new File(newFile)));
                //System.out.println(file.getAbsolutePath());
            }
            
            
            
            
        }).start();

    }

} 



Windows结果
false
true
true
false
temp文件rename可能出错,文件内容是否缺失未检查

Linux结果 
3441
true
6049
true
9298
true
13684
true
18948
true
23111
true
27620
true
32796
true
37649
true
42505
true
46032
true
50162
true
55093
true
60190
true
65479
true
69765
true
72820
true
75923
true
77882
true
78918
true
81792
true
85466
true
88849
true
92514
true
95177
true
98063
true
100907
true
103889
true
107756
true
110590
true
115618
true
119971
true
124234
true
128715
true
133401
true
137259
true
141025
true
145575
true
150916
true
156253
true
161660
true
165849
true
171009
true
176014
true
181036
true
183053
true
187926
true
.....
temp文件rename不出错,文件内容也没有缺失

依赖操作系统来控制文件的多线程访问,是不合理的。这符合我的预期。不过Linux提供了比windows更好的保护机制,这是为啥现在的系统一直工作我又百思不得其解的原因可见多测试比想当然更重要!!!

import java.io.File;
import java.io.IOException;


public class Test2 {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        File file = new File("test");
        //file.createNewFile();
        
        File file2 = new File("test2");
        file2.createNewFile();
        
        
        System.out.println(file2.renameTo(file));
    }

}

test文件已存在,windows报错,linux直接覆盖原文件。。。好狠


更多推荐

Java File 操作在windows和linux的不同