2009-07-18 152 views
1

我在Java中的目錄中移動文件時遇到問題。問題是,我不明白爲什麼程序的行爲方式。以下是我的真實程序的(輕微)修改。使用Java將文件從一個目錄移動到另一個目錄

我遍歷目錄的目錄。在每個遍歷目錄 中都有文本文件,我想將其移動到遍歷目錄的兩個子目錄中。我創建了這兩個目錄(trainingDatatestData)。我想將30個文件移入testData目錄,其中60個文件位於trainingData目錄中。爲此,我製作了兩個for循環。

在下面的代碼中,我先把循環移動到trainingData。好消息是,所有這60個文件真的被轉移到trainingData。但是,第二個循環似乎沒有做任何事情 - 沒有任何這30個剩餘文件的文件被移動。這30個文件繼續保留在原始(遍歷)目錄中。

此外,很奇怪的是,當我交換兩個循環時 - 將30個文件放在首位,另一個放在其後,然後將30個文件正確移入testData,但是,30的其他60個文件移動到trainingData目錄中,其餘30個文件保留在原始(遍歷)目錄中。

該程序仍然沒有做我想做的事(只是部分),但是,困擾我的是我不明白爲什麼當我交換兩個循環的地方時這種差異(??)。代碼是相同的,並應該工作相同,不是嗎?

感謝您查看代碼的時間,如果有必要,我願意提供更多的代碼和解釋。

File[] reviews = null; 
for(File sortedRevDir : sortedRevDirs) { 
    reviews = sortedRevDir.listFiles(); 
    int numFiles = 90; 
    int numTwoThirds = 60; 
    int numOneThirds = numFiles - numTwoThirds;  

    String trainingDir = sortedRevDir.getAbsolutePath() + "/trainingData"; 
    File trDir = new File(trainingDir); 
    trDir.mkdir(); 
    String testDir = sortedRevDir.getAbsolutePath() + "/testData"; 
    File tsDir = new File(testDir); 
    tsDir.mkdir(); 

    for(int i = 0; i < numTwoThirds; i++) { 
     File review = reviews[i]; 
     if(!review.isDirectory()) { 
       File reviewCopied = new File(trDir + "/" + review.getName()); 
       review.renameTo(reviewCopied); 
     } 
    } 
    for(int j = 0; j < numOneThird; j++) { 
     File review = reviews[j]; 
     if(!review.isDirectory()) { 
      File reviewCopied = new File(tsDir + "/" + review.getName()); 
      review.renameTo(reviewCopied); 
     } 
    } 
} 
+1

一個快速的樣式建議:「numFiles」會更好,像「fileQuantity」。因爲它可能是包含數字的文件列表,與文件相關的數字列表或其他內容,如果不查看聲明,我也不會知道。 numOneThird會更簡單,因爲numFiles/3和numTwoThirds會更簡單,因爲numFiles * 2/3。您所做的所有操作都是用單詞中的相同語句替換數學語句。理想情況下,變量名應該給出一個線索,說明爲什麼你要把90分成組。 – Imagist 2009-07-18 22:18:05

+0

謝謝,我會記住它。 – user42155 2009-07-19 00:32:29

回答

1

做的第二環如下:

for(int j = numTwoThirds; j < numTwoThirds + numOneThird; j++) { 

的問題是,在這兩個循環,就指數相同Filearray秒。當您物理移動文件時,它不會從陣列中移除。它只是呆在那裏。在第二個循環中,它嘗試移動已移動的文件。所以這就是爲什麼在第二個循環中,您的索引變量必須從第一個循環中的最終值繼續。

這也解釋了爲什麼當您交換兩個循環時,只有30個文件從原始目錄複製:前30個文件被忽略,因爲它們已被複制;其餘30個按預期複製。

或者,您可以在兩個循環之間執行另一個reviews = sortedRevDir.listFiles();以保持循環更簡單,但這在性能方面有點浪費,因爲這是另一種IO操作,它不是必需的。

+0

嗨jqno,非常感謝!我已經按照你的建議改變了for循環,它完美的工作!也感謝你的解釋,我現在清楚了以前發生了什麼。 – user42155 2009-07-18 21:40:59

+0

其實,當程序試圖刪除一個文件(在第二個循環中)時,爲什麼我沒有收到錯誤消息?你說,它忽略了這樣刪除的文件(它)。在第二個循環中,變量評論指向評論[i],讓我們說評論[2]。由於數組沒有改變,這意味着我們現在創建對同一個對象的第二個引用,對吧? (第一個參考來自第一個循環)。我不明白爲什麼removeTo()不會在無法刪除文件時發生抱怨。 – user42155 2009-07-19 00:41:17

+2

File.renameTo不會拋出異常,它會返回一個布爾值。我的猜測是這些調用返回false,但你沒有注意到,因爲你的代碼沒有檢查錯誤。不,我不知道爲什麼java.io方法傾向於返回布爾值而不是使用異常,但是這個問題之前也讓我感到困擾。 – jsight 2009-07-19 03:16:50

2

請記住,如果目標目錄不在同一個文件系統上,File.renameTo(dest)可能(可能會)失敗。

在這種情況下,您需要實現複製和刪除語義;

+0

謝謝。爲什麼會失敗? – user42155 2009-07-18 23:15:33

+2

因爲使用的底層重命名進程無法保證在文件系統中正常工作。從javadocs:「這個方法的行爲的許多方面本質上是平臺依賴的:重命名操作可能無法將文件從一個文件系統移動到另一個文件系統,它可能不是原子性的,並且如果文件可能不成功與目標抽象路徑名已存在。應始終檢查返回值以確保重命名操作成功。「 – jsight 2009-07-19 03:18:36

相關問題