2009-07-18 172 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

相关问题