我想复制一个文件并替换现有文件。问题是如果该文件正被另一个程序使用,则会发生AccessDeniedException,并删除现有文件。如果复制失败,我希望保留现有文件。以下代码演示了此问题。 (注意Java Files.copy replace existing deletes file entirely中也报告了这个问题,但OP没有提供重现问题的方法。)
public void copyFile(){
Path workingCopy = null;
//Create a plain text file called example-file-error.txt, add some text to the file, and save it in user.home
Path path = Paths.get(System.getProperty("user.home"), "example-file-error.txt");
try{
workingCopy = Files.createTempFile(path.getParent(), "temp", ".txt");
//Create a locked file, but the lock is actually created by a separate program
FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true);
Files.copy(workingCopy, path, StandardCopyOption.REPLACE_EXISTING);
}catch(Exception ex){
ex.printStackTrace();
}finally{
try{
Files.deleteIfExists(workingCopy);
}catch(IOException ex){
ex.printStackTrace();
}
}
}
如果复制失败,有没有办法保留原始文件?或者,有没有办法在尝试复制之前等待访问文件?
答案 0 :(得分:0)
从finally中删除此行Files.deleteIfExists(workingCopy);
并将其放在try子句的末尾
public void copyFile() {
Path workingCopy = null; //Create a plain text file called example-file-error.txt, add some text to the file, and save it in user.home
Path path = Paths.get(System.getProperty("user.home"), "example-file-error.txt");
try{
workingCopy = Files.createTempFile(path.getParent(), "temp", ".txt"); //Create a locked file, but the lock is actually created by a separate program
FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true);
Files.copy(workingCopy, path, StandardCopyOption.REPLACE_EXISTING);
Files.deleteIfExists(workingCopy);
}catch(Exception ex)
{ ex.printStackTrace(); }
答案 1 :(得分:0)
解决方案是使用Files.move()而不是Files.copy()以及选项StandardCopyOption.REPLACE_EXISTING和StandardCopyOption.ATOMIC_MOVE。原子移动可防止在发生异常时删除目标文件。该解决方案适用于Windows 10,但不保证原子移动适用于所有操作系统。我不确定哪些人不允许这个选项。解决方案如下。
public void copyFile(){
Path workingCopy = null;
//Create a plain text file called example-file-error.txt, add some text to the file, and save it in user.home
Path path = Paths.get(System.getProperty("user.home"), "example-file-error.txt");
try{
workingCopy = Files.createTempFile(path.getParent(), "temp", ".txt");
//Create a locked file, but the lock is actually created by a separate program
FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true);
//This line seems to be the solution to the problem
Files.move(workingCopy, path, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
}catch(IOException ex){
ex.printStackTrace();
}finally{
try{
Files.deleteIfExists(workingCopy);
}catch(IOException ex){
ex.printStackTrace();
}
}
}
答案 2 :(得分:0)
我遇到了同样的问题。我以前找不到检查文件可访问性的方法。 (当然我测试了Attributes和Files.isWritable等等,但这没有帮助)。 Files.delete(文件)也以AccessDeniedException结束,但该文件在Windows文件系统上被删除。但是之后的Files.copy()也会抛出AccessDeniedException。
最后,我通过使用另一个API(来自How to copy file from one location to another location?的文件频道)来处理问题。
private static void copyFileUsingChannel(File source, File dest) throws IOException {
FileChannel sourceChannel = null;
FileChannel destChannel = null;
try {
sourceChannel = new FileInputStream(source).getChannel();
destChannel = new FileOutputStream(dest).getChannel();
destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
}finally{
sourceChannel.close();
destChannel.close();
}
}