12

今日、ユーティリティ クラスの 1 つで問題が発生しました。これはファイルのヘルパーであり、いくつかの静的ファイル コピー ルーチンが含まれています。以下は、テスト方法とともに抽出された関連する方法です。

問題は、setLastModified 呼び出しが失敗して、false が返されることがあるということです。

私の PC (Windows 7、最新の Java) では、「setLastModified failed」というメッセージが表示されることがあります (1000 回中約 25 回)。

FileChannel.close 呼び出しを削除することで問題を回避しましたが、それが正しい解決策であっても、なぜこれが起こっているのかを理解したいと思っています。

他の誰かが同じ問題を抱えていますか?

private void testCopy() throws FileNotFoundException, IOException {
  File src = new File("C:\\Public\\Test-Src.txt");
  File dst = new File("C:\\Public\\Test-Dst.txt");

  for (int i = 0; i < 1000; i++) {
    copyFile(src, dst);
  }
}

public static void copyFile(final File from, final File to) throws FileNotFoundException, IOException {
  final String tmpName = to.getAbsolutePath() + ".tmp";
  // Copy to a .tmp file.
  final File tmp = new File(tmpName);
  // Do the transfer.
  transfer(from, tmp);
  // Preserve time.
  if (!tmp.setLastModified(from.lastModified())) {
    System.err.println("setLastModified failed!");
  }
  // In case there's one there already.
  to.delete();
  // Rename it in.
  tmp.renameTo(to);
}

public static void transfer(final File from, final File to) throws IOException {
  FileInputStream in = null;
  FileOutputStream out = null;
  try {
    in = new FileInputStream(from);
    out = new FileOutputStream(to);
    transfer(in, out);
  } finally {
    if (null != in) {
      in.close();
    }
    if (null != out) {
      out.close();
    }
  }
}

public static void transfer(final FileInputStream from, final FileOutputStream to) throws IOException {
  FileChannel srcChannel = null;
  FileChannel dstChannel = null;
  //try {
    srcChannel = from.getChannel();
    dstChannel = to.getChannel();
    srcChannel.transferTo(0, srcChannel.size(), dstChannel);
  //} finally {
  //  if (null != dstChannel) {
  //    dstChannel.close();
  //  }
  //  if (null != srcChannel) {
  //    srcChannel.close();
  //  }
  }
}

編集:を閉じるStreamsと.FileChannelFileChannelStream

4

2 に答える 2

11

Java ライブラリ ソースを保持しているさまざまなサイトを調査した結果、FileChannel.close最終的に親オブジェクトのFileInputStream.closeまたはを呼び出すように見えます。FileOutputStream.close

これは、FileChannel または Stream のいずれかを閉じる必要があることを示唆していますが、両方を閉じる必要はありません。

これを考慮して、元の投稿を 1 つの正しい方法を反映するように変更しています。つまり、Streams ではなく s を閉じChannelます。

于 2011-11-21T11:10:21.230 に答える
3

Java 7 を使用している場合は、この操作にFiles.copy(Path source, Path target, CopyOption... options)を使用して、独自の実装の記述、テスト、およびデバッグを回避できます。

または、 Apache Commons IOなどの外部ライブラリの使用を検討してください。特に、FileUtils.copyFile(File srcFile, File destFile) は興味深いものです。

/** 
 * Copies a file to a new location preserving the file date.
 * [...]
 * @param srcFile  an existing file to copy, must not be <code>null</code>
 * @param destFile  the new file, must not be <code>null</code>
 * [...]
 */
public static void copyFile(File srcFile, File destFile) throws IOException
于 2011-11-12T18:25:46.403 に答える