在Java中解压到树映射中
我的问题相对简单。有人知道一个免费库(LGPL)能够将压缩后的文件结构解压缩到Java的树状图(或类似的可迭代结构)中吗 关键是,我自己可以做到这一点,但我不想重新发明已经很好的驾驶轮:) 提前谢谢在Java中解压到树映射中,java,tree,zip,directory-structure,Java,Tree,Zip,Directory Structure,我的问题相对简单。有人知道一个免费库(LGPL)能够将压缩后的文件结构解压缩到Java的树状图(或类似的可迭代结构)中吗 关键是,我自己可以做到这一点,但我不想重新发明已经很好的驾驶轮:) 提前谢谢 所以我的问题是,我有一个zip文件,包含多个文件和目录,其中可能包含更多的文件。我要寻找的是一种方便的方法,如何将这种树结构提取到对象图中,无论它是否是树图。例如:aHashMap:{'root'=>'HashMap:{'file1.png'=>byte[]content}怎么样?它听起来像是一个
所以我的问题是,我有一个zip文件,包含多个文件和目录,其中可能包含更多的文件。我要寻找的是一种方便的方法,如何将这种树结构提取到对象图中,无论它是否是树图。例如:a
HashMap:{'root'=>'HashMap:{'file1.png'=>byte[]content}
怎么样?它听起来像是一个非常简单的包装器,应该可以做您想要的事情。您可以使用java.util.ZipFile使用ZipFile,获取其内容并将当前内容转换为java.io.File,然后检查它是否为Dir,如果是,则在该aslo中迭代,并且可以在运行时将这些内容存储在TreeMap中
ZipFile myzip = new ZipFile (new File("pathToMyZipFile.zip"));
Enumeration zipEnumerator = myzip.entries();
while(zipEnumerator.hasMoreElements())
{
ZipENtry ze= zipEnumerator.nextElement();
if(ze.isDirectory())
{
// recurse
}
else {
// add it to treeMap
}
}
所以我的问题是,我有一个zip文件,包含多个文件和目录,其中可能包含更多的文件。
我要寻找的是一种方便的方法,如何将这种树结构提取到对象图中,无论它是否是树图。
例如:HashMap:{'root','HashMap:{'file1.png'=>byte[]content}
关于另一个问题,javaapi中没有单一的“树”数据结构(树接口),因为每次使用都需要其他特性。
例如,您建议的HashMap树不能以类型保存的方式实现——您可能需要在某个地方使用包装器对象
我不知道是否已经有了一个类似于树的zip文件视图来回答你的问题,但是一旦你定义了你想要的树接口,创建它并不困难
因此,这里有一个示例类,它可以实现您想要的功能(据我所知)
(你需要一个支持unicode的终端和System.out的unicode编码。)好吧,ZipFile会给我一组ZipEntry对象,但我想要一个映射到zip存档本身目录结构的结构。哦,我明白了。那么你可能想澄清这个问题。另外,作为参考,Java
TreeMap
只是一个key=>value
map;它不公开任何树状接口。好的,很抱歉描述不正确。所以我的问题是,我有一个zip文件,包含多个文件和目录,其中可能包含更多的文件。我要寻找的是一种方便的方法,如何将这种树结构提取到对象图中,无论它是否是树图。例如:一个HashMap:{'root','HashMap:{'file1.png'=>byte[]content}}当然,但整个过程听起来像是一个非常常用的任务。因此,我想知道是否有任何用于此类情况的util库(如apache commons)。“递归”点是复杂性开始的地方,ZipEntry
不允许访问其子条目(如果有,您已经有了树API)。好的,现在我看到了实际问题。谢谢我只是认为可能有某种通用库提供了一个HashMap树,例如文件包装器。关键是,我需要以正确的顺序创建任何子目录,以便在虚拟文件系统中创建它们(否则我会使用File#mkdirs())。。。我不确定“正确的顺序”,但你现在可以随心所欲地穿过这棵树了。现在我感到震惊。非常感谢你!谢谢你!从未想过有人会提出一个实际的实现。我会调查的!我真的很困惑,这个基本特性没有库功能。如果我在处理文件,我通常对文件树结构感兴趣。认为我们必须为这个重新发明轮子。。。
import java.io.*;
import java.util.*;
import java.util.zip.*;
/**
* A immutable wrapper around {@link ZipEntry} allowing
* simple access of the childs of directory entries.
*/
public class ZipNode {
private ZipNode parent;
private Map<String,ZipNode> children;
private boolean directory;
/**
* the corresponding Zip entry. If null, this is the root entry.
*/
private ZipEntry entry;
/** the ZipFile from where the nodes came. */
private ZipFile file;
private ZipNode(ZipFile f, ZipEntry entry) {
this.file = f;
this.entry = entry;
if(entry == null || entry.isDirectory()) {
directory = true;
children = new LinkedHashMap<String, ZipNode>();
}
else {
directory = false;
children = Collections.emptyMap();
}
}
/**
* returns the last component of the name of
* the entry, i.e. the file name. If this is a directory node,
* the name ends with '/'. If this is the root node, the name
* is simply "/".
*/
public String getName() {
if(entry == null)
return "/";
String longName = entry.getName();
return longName.substring(longName.lastIndexOf('/',
longName.length()-2)+1);
}
/**
* gets the corresponding ZipEntry to this node.
* @return {@code null} if this is the root node (which has no
* corresponding entry), else the corresponding ZipEntry.
*/
public ZipEntry getEntry() {
return entry;
}
/**
* Gets the ZipFile, from where this ZipNode came.
*/
public ZipFile getZipFile() {
return file;
}
/**
* returns true if this node is a directory node.
*/
public boolean isDirectory() {
return directory;
}
/**
* returns this node's parent node (null, if this is the root node).
*/
public ZipNode getParent() {
return parent;
}
/**
* returns an unmodifiable map of the children of this node,
* mapping their relative names to the ZipNode objects.
* (Names of subdirectories end with '/'.)
* The map is empty if this node is not a directory node.
*/
public Map<String,ZipNode> getChildren() {
return Collections.unmodifiableMap(children);
}
/**
* opens an InputStream on this ZipNode. This only works when
* this is not a directory node, and only before the corresponding
* ZipFile is closed.
*/
public InputStream openStream()
throws IOException
{
return file.getInputStream(entry);
}
/**
* a string representation of this ZipNode.
*/
public String toString() {
return "ZipNode [" + entry.getName() + "] in [" + file.getName() + "]";
}
/**
* creates a ZipNode tree from a ZipFile
* and returns the root node.
*
* The nodes' {@link #openStream()} methods are only usable until the
* ZipFile is closed, but the structure information remains valid.
*/
public static ZipNode fromZipFile(ZipFile zf) {
return new ZipFileReader(zf).process();
}
/**
* Helper class for {@link ZipNode#fromZipFile}.
* It helps creating a tree of ZipNodes from a ZipFile.
*/
private static class ZipFileReader {
/**
* The file to be read.
*/
private ZipFile file;
/**
* The nodes collected so far.
*/
private Map<String, ZipNode> collected;
/**
* our root node.
*/
private ZipNode root;
/**
* creates a new ZipFileReader from a ZipFile.
*/
ZipFileReader(ZipFile f) {
this.file = f;
this.collected = new HashMap<String, ZipNode>();
collected.put("", root);
root = new ZipNode(f, null);
}
/**
* reads all entries, creates the corresponding Nodes and
* returns the root node.
*/
ZipNode process() {
for(Enumeration<? extends ZipEntry> entries = file.entries();
entries.hasMoreElements(); ) {
this.addEntry(entries.nextElement());
}
return root;
}
/**
* adds an entry to our tree.
*
* This may create a new ZipNode and then connects
* it to its parent node.
* @returns the ZipNode corresponding to the entry.
*/
private ZipNode addEntry(ZipEntry entry) {
String name = entry.getName();
ZipNode node = collected.get(name);
if(node != null) {
// already in the map
return node;
}
node = new ZipNode(file, entry);
collected.put(name, node);
this.findParent(node);
return node;
}
/**
* makes sure that the parent of a
* node is in the collected-list as well, and this node is
* registered as a child of it.
* If necessary, the parent node is first created
* and added to the tree.
*/
private void findParent(ZipNode node) {
String nodeName = node.entry.getName();
int slashIndex = nodeName.lastIndexOf('/', nodeName.length()-2);
if(slashIndex < 0) {
// top-level-node
connectParent(root, node, nodeName);
return;
}
String parentName = nodeName.substring(0, slashIndex+1);
ZipNode parent = addEntry(file.getEntry(parentName));
connectParent(parent, node, nodeName.substring(slashIndex+1));
}
/**
* connects a parent node with its child node.
*/
private void connectParent(ZipNode parent, ZipNode child,
String childName) {
child.parent = parent;
parent.children.put(childName, child);
}
} // class ZipFileReader
/**
* test method. Give name of zip file as command line argument.
*/
public static void main(String[] params)
throws IOException
{
if(params.length < 1) {
System.err.println("Invocation: java ZipNode zipFile.zip");
return;
}
ZipFile file = new ZipFile(params[0]);
ZipNode root = ZipNode.fromZipFile(file);
file.close();
root.printTree("", " ", "");
}
/**
* prints a simple tree view of this ZipNode.
*/
private void printTree(String prefix,
String self,
String sub) {
System.out.println(prefix + self + this.getName());
String subPrefix = prefix + sub;
// the prefix strings for the next level.
String nextSelf = " ├─ ";
String nextSub = " │ ";
Iterator<ZipNode> iterator =
this.getChildren().values().iterator();
while(iterator.hasNext()) {
ZipNode child = iterator.next();
if(!iterator.hasNext() ) {
// last item, without the "|"
nextSelf = " ╰─ ";
nextSub = " ";
}
child.printTree(subPrefix, nextSelf, nextSub);
}
}
}
/
├─ META-INF/
│ ╰─ MANIFEST.MF
╰─ de/
╰─ fencing_game/
├─ start/
│ ├─ Runner.class
│ ├─ ServerMain$1.class
│ ├─ ServerMain.class
│ ╰─ package-info.class
├─ log/
│ ├─ Log$1.class
│ ├─ Log.class
│ ├─ LogImplClient.class
│ ├─ Loggable.class
│ ╰─ package-info.class
╰─ tools/
╰─ load/
├─ ServiceTools$1.class
├─ ServiceTools$2.class
├─ ServiceTools$3.class
├─ ServiceTools.class
╰─ TwoParentClassLoader.class