1. 程式人生 > >Java File 操作在windows和linux的不同

Java File 操作在windows和linux的不同

使用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直接覆蓋原檔案。。。好狠