Java Zip文件系统提供程序:远程驱动器上的ReadOnly [Windows]

时间:2014-07-21 10:58:52

标签: java filesystems zip java.nio.file

我遇到Zip File System Provider的问题:如果zip文件位于远程驱动器上(映射与否似乎无关),则虚拟文件系统是只读的,尽管文件本身不是。我写了一个最小的示例代码:

public static void main(String[] args) throws IOException {
    File workingDir = new File(args[0]);
    File source = new File(workingDir, "in.zip");
    File target = new File(workingDir, "out.zip");
    Files.copy(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);

    try (FileSystem zipfs = FileSystems.newFileSystem(target.toPath(), null)) {
        Path pathInZipfile = zipfs.getPath("test.xml");
        System.out.println("zipfile writable: " + target.canWrite());
        System.out.println("zipFS writable: " + !zipfs.isReadOnly());
        Files.delete(pathInZipfile);
        System.out.println("File successfully deleted");   
    } catch (IOException e) {
        e.printStackTrace();
    }
}

如果workingDir是本地目录,一切正常。但是,如果它是(映射的)远程驱动器,我得到:

zipfile writable: true
zipFS writable: false
Exception in thread "main" java.nio.file.ReadOnlyFileSystemException
    at com.sun.nio.zipfs.ZipFileSystem.checkWritable(ZipFileSystem.java:155)
    at com.sun.nio.zipfs.ZipFileSystem.deleteFile(ZipFileSystem.java:1335)
    at com.sun.nio.zipfs.ZipPath.delete(ZipPath.java:655)
    at com.sun.nio.zipfs.ZipFileSystemProvider.delete(ZipFileSystemProvider.java:206)
    at java.nio.file.Files.delete(Unknown Source)
    at zipfs.ZipFS.main(ZipFS.java:23)

我做错了吗?这不可能吗?有解决方法吗?

3 个答案:

答案 0 :(得分:0)

我遇到了同样的事情,我查看了JDK代码。

首饰

在ZipFileSystem.java中有三个相关的行:

<RelativeLayout    
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"   
    android:layout_width="match_parent"
    android:layout_height="match_parent"   
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    <ImageView
        android:src="@drawable/mv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

zfPath是一个Path对象。 Windows FileSystem提供程序中的某些内容阻止对zip存档路径的写访问。似乎没有什么可以做的。

解决方法

我用作解决方法的是:

  1. 在临时文件夹中创建zip档案
  2. 填充zip存档
  3. 将临时文件复制到原始映射驱动器位置
  4. 只要映射的驱动器在zip文件系统之外的上下文中是可写的,这种方法就可以工作。

答案 1 :(得分:0)

我们遇到了完全相同的问题,并设计了一些野蛮的解决方案。 FileSystems.newFileSystem(Path) 接受 Path 接口,因此可以满足它包装真正的 Path 实例。

这是实现所需 FileSysteProvider.checkAccess() 的解决方案:

  private static FileSystem createZip(Path zipPath)
    throws Exception
  {
    var fileSystem = zipPath.getFileSystem();
    var provider = fileSystem.provider();
    
    return FileSystems.newFileSystem(
      new Path()
      {
        private Path path(Path path)
        {
          return this == path ? zipPath : path;
        }
        
        @Override
        public FileSystem getFileSystem()
        {
          return new FileSystem()
          {
            public Set<String> supportedFileAttributeViews()
            {
              return fileSystem.supportedFileAttributeViews();
            }
            
            @Override
            public FileSystemProvider provider()
            {
              return new FileSystemProvider()
              {
                @Override
                public void setAttribute(
                  Path path, 
                  String attribute, 
                  Object value,
                  LinkOption... options) 
                  throws IOException
                {
                  provider.setAttribute(path(path), attribute, value, options);
                }
                
                @Override
                public Map<String, Object> readAttributes(
                  Path path, 
                  String attributes,
                  LinkOption... options) 
                  throws IOException
                {
                  return provider.
                    readAttributes(path(path), attributes, options);
                }
                
                @Override
                public <A extends BasicFileAttributes> A readAttributes(
                  Path path,
                  Class<A> type, 
                  LinkOption... options) 
                  throws IOException
                {
                  return provider.readAttributes(path(path), type, options);
                }
                
                @Override
                public FileSystem newFileSystem(URI uri, Map<String, ?> env)
                  throws IOException
                {
                  return provider.newFileSystem(uri, env);
                }
                
                @Override
                public DirectoryStream<Path> newDirectoryStream(
                  Path dir,
                  Filter<? super Path> filter) 
                  throws IOException
                {
                  return provider.newDirectoryStream(dir, filter);
                }
                
                @Override
                public SeekableByteChannel newByteChannel(
                  Path path,
                  Set<? extends OpenOption> options, 
                  FileAttribute<?>... attrs)
                  throws IOException
                {
                  return provider.newByteChannel(path(path), options, attrs);
                }
                
                @Override
                public void move(
                  Path source, 
                  Path target, 
                  CopyOption... options)
                  throws IOException
                {
                  provider.move(path(source), path(target), options);
                }
                
                @Override
                public boolean isSameFile(Path path, Path path2) 
                  throws IOException
                {
                  return provider.isSameFile(path(path), path(path2));
                }
                
                @Override
                public boolean isHidden(Path path) 
                  throws IOException
                {
                  return provider.isHidden(path(path));
                }
                
                @Override
                public String getScheme()
                {
                  return provider.getScheme();
                }
                
                @Override
                public Path getPath(URI uri)
                {
                  return provider.getPath(uri);
                }
                
                @Override
                public FileSystem getFileSystem(URI uri)
                {
                  return provider.getFileSystem(uri);
                }
                
                @Override
                public FileStore getFileStore(Path path) 
                  throws IOException
                {
                  return provider.getFileStore(path(path));
                }
                
                @Override
                public <V extends FileAttributeView> V getFileAttributeView(
                  Path path,
                  Class<V> type, 
                  LinkOption... options)
                {
                  return provider.
                    getFileAttributeView(path(path), type, options);
                }
                
                @Override
                public void delete(Path path) 
                  throws IOException
                {
                  provider.delete(path(path));
                }
                
                @Override
                public void createDirectory(Path dir, FileAttribute<?>... attrs)
                    throws IOException
                {
                  provider.createDirectory(path(dir), attrs);
                }
                
                @Override
                public void copy(
                  Path source, 
                  Path target, 
                  CopyOption... options)
                  throws IOException
                {
                  provider.copy(path(source), path(target), options);                      
                }
                
                @Override
                public void checkAccess(Path path, AccessMode... modes)
                  throws IOException
                {
                  if ((modes != null) && 
                    (modes.length == 1) && 
                    (modes[0] == AccessMode.WRITE))
                  {
                    return;
                  }
                  
                  provider.checkAccess(path(path), modes);
                }
              };
            }
            
            @Override
            public WatchService newWatchService()
              throws IOException
            {
              return fileSystem.newWatchService();
            }
            
            @Override
            public boolean isReadOnly()
            {
              return false;
            }
            
            @Override
            public boolean isOpen()
            {
              return fileSystem.isOpen();
            }
            
            @Override
            public UserPrincipalLookupService getUserPrincipalLookupService()
            {
              return fileSystem.getUserPrincipalLookupService();
            }
            
            @Override
            public String getSeparator()
            {
              return fileSystem.getSeparator();
            }
            
            @Override
            public Iterable<Path> getRootDirectories()
            {
              return fileSystem.getRootDirectories();
            }
            
            @Override
            public PathMatcher getPathMatcher(String syntaxAndPattern)
            {
              return fileSystem.getPathMatcher(syntaxAndPattern);
            }
            
            @Override
            public Path getPath(String first, String... more)
            {
              return fileSystem.getPath(first, more);
            }
            
            @Override
            public Iterable<FileStore> getFileStores()
            {
              return fileSystem.getFileStores();
            }
            
            @Override
            public void close() throws IOException
            {
              fileSystem.close();                  
            }
          };
        }
  
        @Override
        public boolean isAbsolute()
        {
          return zipPath.isAbsolute();
        }
  
        @Override
        public Path getRoot()
        {
          return zipPath.getRoot();
        }
  
        @Override
        public Path getFileName()
        {
          return zipPath.getFileName();
        }
  
        @Override
        public Path getParent()
        {
          return zipPath.getParent();
        }
  
        @Override
        public int getNameCount()
        {
          return zipPath.getNameCount();
        }
  
        @Override
        public Path getName(int index)
        {
          return zipPath.getName(index);
        }
  
        @Override
        public Path subpath(int beginIndex, int endIndex)
        {
          return zipPath.subpath(beginIndex, endIndex);
        }
  
        @Override
        public boolean startsWith(Path other)
        {
          return zipPath.startsWith(other);
        }
  
        @Override
        public boolean endsWith(Path other)
        {
          return zipPath.endsWith(other);
        }
  
        @Override
        public Path normalize()
        {
          return zipPath.normalize();
        }
  
        @Override
        public Path resolve(Path other)
        {
          return zipPath.relativize(other);
        }
  
        @Override
        public Path relativize(Path other)
        {
          return zipPath.relativize(other);
        }
  
        @Override
        public URI toUri()
        {
          return zipPath.toUri();
        }
  
        @Override
        public Path toAbsolutePath()
        {
          return zipPath.toAbsolutePath();
        }
  
        @Override
        public Path toRealPath(LinkOption... options) 
          throws IOException
        {
          return zipPath.toRealPath(options);
        }
  
        @Override
        public WatchKey register(
          WatchService watcher, 
          Kind<?>[] events,
          Modifier... modifiers) 
          throws IOException
        {
          return zipPath.register(watcher, events, modifiers);
        }
  
        @Override
        public int compareTo(Path other)
        {
          return zipPath.compareTo(other);
        }
      }, 
      Map.of("create", "true"));
  }

这更像是一个 hack 但我们认为它解决了原始 ZipFileSystem

中的错误

答案 2 :(得分:-1)

尝试使用反射将readOnly中的私人字段ZipFileSystem设置为false