我的问题是,我有一个zip文件,其中包含多个文件和目录,这些目录可能包含更多的文件。
我想要的是一种方便的方法,将这个树形结构提取到对象图中,无论它是TreeMap还是其他什么。
例如:一个HashMap:{'root','HashMap:{'file1.png' => byte [] content}}。
正如我之前在另一个问题上回答的
(链接)那样,在Java API中没有单一的“树”数据结构(树接口),因为每个使用都需要其他功能。例如,您提出的HashMap-tree不能以类型安全的方式实现-您需要在某个地方使用包装器对象。
我不知道是否已经有了一个类似于zip文件的树状视图,以回答您的问题,但只要定义所需的树形接口,就不难创建它。
所以,这里有一个示例类可以做到你想要的(根据我理解的)。
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class ZipNode {
private ZipNode parent;
private Map<String,ZipNode> children;
private boolean directory;
private ZipEntry entry;
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();
}
}
public String getName() {
if(entry == null)
return "/";
String longName = entry.getName();
return longName.substring(longName.lastIndexOf('/',
longName.length()-2)+1);
}
public ZipEntry getEntry() {
return entry;
}
public ZipFile getZipFile() {
return file;
}
public boolean isDirectory() {
return directory;
}
public ZipNode getParent() {
return parent;
}
public Map<String,ZipNode> getChildren() {
return Collections.unmodifiableMap(children);
}
public InputStream openStream()
throws IOException
{
return file.getInputStream(entry);
}
public String toString() {
return "ZipNode [" + entry.getName() + "] in [" + file.getName() + "]";
}
public static ZipNode fromZipFile(ZipFile zf) {
return new ZipFileReader(zf).process();
}
private static class ZipFileReader {
private ZipFile file;
private Map<String, ZipNode> collected;
private ZipNode root;
ZipFileReader(ZipFile f) {
this.file = f;
this.collected = new HashMap<String, ZipNode>();
collected.put("", root);
root = new ZipNode(f, null);
}
ZipNode process() {
for(Enumeration<? extends ZipEntry> entries = file.entries();
entries.hasMoreElements(); ) {
this.addEntry(entries.nextElement());
}
return root;
}
private ZipNode addEntry(ZipEntry entry) {
String name = entry.getName();
ZipNode node = collected.get(name);
if(node != null) {
return node;
}
node = new ZipNode(file, entry);
collected.put(name, node);
this.findParent(node);
return node;
}
private void findParent(ZipNode node) {
String nodeName = node.entry.getName();
int slashIndex = nodeName.lastIndexOf('/', nodeName.length()-2);
if(slashIndex < 0) {
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));
}
private void connectParent(ZipNode parent, ZipNode child,
String childName) {
child.parent = parent;
parent.children.put(childName, child);
}
}
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("", " ", "");
}
private void printTree(String prefix,
String self,
String sub) {
System.out.println(prefix + self + this.getName());
String subPrefix = prefix + sub;
String nextSelf = " ├─ ";
String nextSub = " │ ";
Iterator<ZipNode> iterator =
this.getChildren().values().iterator();
while(iterator.hasNext()) {
ZipNode child = iterator.next();
if(!iterator.hasNext() ) {
nextSelf = " ╰─ ";
nextSub = " ";
}
child.printTree(subPrefix, nextSelf, nextSub);
}
}
}
它有一个主方法用于测试,其中一个我的jar文件的输出如下:
/
├─ 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
(不过,您需要一个支持Unicode的终端和一个使用Unicode编码的System.out。)