写入ZIP文件的文件仅在运行时可用[Java]

时间:2017-08-08 01:20:20

标签: java path filesystems java-7 nio

我遇到使用Java 7 FileSystemFiles API将二进制文件写入简单ZIP存档的问题。

执行写入操作时出现问题,完全没有异常,文件没有写入ZIP存档,但在运行时可用(Files.exists(backup)返回true并且可以读取该文件使用Files.readAllBytes(backup))。

当程序关闭并重新启动时,该文件不再可用。

这种方法应该创建任何路径的备份,无论谁是FileSystem提供商,'失败'就在ZIP档案中的路径上。

/**
 * Creates backup of path provided by 'file' parameter.
 *
 * @param file input file requiring backup creation
 * @return backup file
 * @throws java.io.IOException thrown in case of unsuccessful backup attempt
 */
public static Path createBackup(Path file) throws IOException {

    FileSystem fileSystem = file.getFileSystem();
    Path backup = fileSystem.getPath(file.toString() + ".BAK");

    return Files.write(backup, Files.readAllBytes(file));

}

public static void main(String... args) {
   try {

      Path f = FileSystems.newFileSystem(Paths.get("a.zip"), null).getPath("file.bin");

      Path backup = createBackup(f);

      System.out.println(Files.exists(backup)); // prints "true"
      System.out.println(new String(Files.readAllBytes(backup))); // prints its bytes
      System.out.println(backup.toString()); // prints "file.bin.BAK"
   } catch (IOException ex) {
      System.err.println(ex);
   }

}

但该文件实际上并不存在于ZIP中。

修改: 我设法让它发挥作用,但是有一个问题。下面的代码关闭文件系统,但正确写入。需要刷新" /"重新打开"文件系统不知怎的。

public static Path createBackup(Path file) throws IOException {

   try(FileSystem fileSystem = file.getFileSystem()) {

      Path backup = fileSystem.getPath(file.toString() + ".BAK");
      return Files.write(backup, Files.readAllBytes(file));

   }
}

当保留原始方法并且在完成所有操作后手动关闭文件系统时,它将删除zip文件并保留zipfstmp***.tmp之类的内容并抛出:

java.nio.file.FileAlreadyExistsException: zipfstmp2666831581340533856.tmp -> a.zip

当tmp文件重命名为" a.zip"时,它是一个有效的修改档案。

2 个答案:

答案 0 :(得分:3)

您应该使用创建文件系统的调用者中的try-with-resource语句关闭。根本不需要在createBackup方法中处理文件系统。

public static Path createBackup(Path file) throws IOException {
    Path backup = file.resolveSibling(file.getFileName().toString()+".BAK");
    return Files.copy(file, backup, StandardCopyOption.REPLACE_EXISTING);
}
public static void main(String... args) {
    try(FileSystem fs = FileSystems.newFileSystem(Paths.get("a.zip"), null)) {
       Path f = fs.getPath("file.bin");
       Path backup = createBackup(f);

       System.out.println(Files.exists(backup)); // prints "true"
       System.out.println(new String(Files.readAllBytes(backup))); // prints its bytes
       System.out.println(backup.toString()); // prints "file.bin.BAK"
    } catch (IOException ex) {
       System.err.println(ex);
    }
}

答案 1 :(得分:0)

下面是一个简单的例子,其中所有逻辑都在main方法中。

解决此问题的关键是使用URI明确说明要使用哪种文件系统提供程序。你可能想知道为什么罐子而不是拉链。在Java中,jar文件实际上是zip文件,但具有不同的文件扩展名。所以java可以使用相同的机制来访问zip文件。

我尝试使用二进制文件和文本文件,它似乎可以在我的Win 10机器上运行。只需更改zip文件的源目录(///e:/a.zip)即可指向zip文件的位置。对我来说,file.bin.BAK被写入了eclipse项目目录的根目录(你可能也希望将其更改为部署)。

import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String... args) {

            //Create URI to define the source as a Zip file.
            //I've used jar because this is essentially a zip file.
            Map<String, String> env = new HashMap<>(); 
            env.put("create", "true"); 
            URI uri = URI.create("jar:file:///e:/a.zip");

            try{

                //Build paths to source file in zip  and externally.
                Path pathInZipfile = FileSystems.newFileSystem(uri, env).getPath("/file.bin");  
                Path extPath  = Paths.get("file.bin.BAK");


                //If file does not exist create it.
                if (! Files.exists(extPath))
                    Files.createFile(extPath);


                //Copy the files over.
                 Files.copy( pathInZipfile, extPath,
                            StandardCopyOption.REPLACE_EXISTING ); 

            }//end try
            catch (IOException ex){
                ex.printStackTrace();
            }//enc catch

    }//end main
}//end class