39 Stimmen

Verzeichnis aus einer jar-Datei kopieren

Ich habe kürzlich eine Anwendung entwickelt und die Jar-Datei erstellt.

Eine meiner Klassen erstellt ein Ausgabeverzeichnis und füllt es mit Dateien aus ihrer Ressource.

Mein Code sieht in etwa so aus:

// Copy files from dir "template" in this class resource to output.
private void createOutput(File output) throws IOException {

    File template = new File(FileHelper.URL2Path(getClass().getResource("template")));
    FileHelper.copyDirectory(template, output);
}

Leider funktioniert das nicht.

Ich habe Folgendes versucht, ohne Erfolg:

  • Verwendung von Streams zur Lösung ähnlicher Probleme bei anderen Klassen, aber es funktioniert nicht mit Verzeichnissen. Der Code war ähnlich zu http://www.exampledepot.com/egs/java.io/CopyFile.html

  • Erstellen der Dateivorlage mit new File(getClass().getResource("template").toUri())

Während ich dies schrieb, dachte ich darüber nach, anstelle eines Vorlagenverzeichnisses im Ressourcenpfad eine Zip-Datei davon zu haben. Tun es auf diese Weise könnte ich die Datei als inputStream erhalten und entpacken Sie es, wo ich brauche. Aber ich bin nicht sicher, ob es der richtige Weg ist.

19voto

jabber Punkte 181

Vielen Dank für die Lösung! Für andere, die folgenden macht keinen Gebrauch von den Hilfsklassen (mit Ausnahme von StringUtils)

/ Ich habe zusätzliche Informationen für diese Lösung hinzugefügt, überprüfen Sie das Ende des Codes, Zegor V /

public class FileUtils {
  public static boolean copyFile(final File toCopy, final File destFile) {
    try {
      return FileUtils.copyStream(new FileInputStream(toCopy),
          new FileOutputStream(destFile));
    } catch (final FileNotFoundException e) {
      e.printStackTrace();
    }
    return false;
  }

  private static boolean copyFilesRecusively(final File toCopy,
      final File destDir) {
    assert destDir.isDirectory();

    if (!toCopy.isDirectory()) {
      return FileUtils.copyFile(toCopy, new File(destDir, toCopy.getName()));
    } else {
      final File newDestDir = new File(destDir, toCopy.getName());
      if (!newDestDir.exists() && !newDestDir.mkdir()) {
        return false;
      }
      for (final File child : toCopy.listFiles()) {
        if (!FileUtils.copyFilesRecusively(child, newDestDir)) {
          return false;
        }
      }
    }
    return true;
  }

  public static boolean copyJarResourcesRecursively(final File destDir,
      final JarURLConnection jarConnection) throws IOException {

    final JarFile jarFile = jarConnection.getJarFile();

    for (final Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements();) {
      final JarEntry entry = e.nextElement();
      if (entry.getName().startsWith(jarConnection.getEntryName())) {
        final String filename = StringUtils.removeStart(entry.getName(), //
            jarConnection.getEntryName());

        final File f = new File(destDir, filename);
        if (!entry.isDirectory()) {
          final InputStream entryInputStream = jarFile.getInputStream(entry);
          if(!FileUtils.copyStream(entryInputStream, f)){
            return false;
          }
          entryInputStream.close();
        } else {
          if (!FileUtils.ensureDirectoryExists(f)) {
            throw new IOException("Could not create directory: "
                + f.getAbsolutePath());
          }
        }
      }
    }
    return true;
  }

  public static boolean copyResourcesRecursively( //
      final URL originUrl, final File destination) {
    try {
      final URLConnection urlConnection = originUrl.openConnection();
      if (urlConnection instanceof JarURLConnection) {
        return FileUtils.copyJarResourcesRecursively(destination,
            (JarURLConnection) urlConnection);
      } else {
        return FileUtils.copyFilesRecusively(new File(originUrl.getPath()),
            destination);
      }
    } catch (final IOException e) {
      e.printStackTrace();
    }
    return false;
  }

  private static boolean copyStream(final InputStream is, final File f) {
    try {
      return FileUtils.copyStream(is, new FileOutputStream(f));
    } catch (final FileNotFoundException e) {
      e.printStackTrace();
    }
    return false;
  }

  private static boolean copyStream(final InputStream is, final OutputStream os) {
    try {
      final byte[] buf = new byte[1024];

      int len = 0;
      while ((len = is.read(buf)) > 0) {
        os.write(buf, 0, len);
      }
      is.close();
      os.close();
      return true;
    } catch (final IOException e) {
      e.printStackTrace();
    }
    return false;
  }

  private static boolean ensureDirectoryExists(final File f) {
    return f.exists() || f.mkdir();
  }
}

Es verwendet nur eine externe Bibliothek der Apache Software Foundation, allerdings sind die verwendeten Funktionen nur :

  public static String removeStart(String str, String remove) {
      if (isEmpty(str) || isEmpty(remove)) {
          return str;
      }
      if (str.startsWith(remove)){
          return str.substring(remove.length());
      }
      return str;
  }
  public static boolean isEmpty(CharSequence cs) {
      return cs == null || cs.length() == 0;
  }

Mein Wissen über die Apache-Lizenz ist begrenzt, aber Sie können diese Methoden in Ihrem Code ohne Bibliothek verwenden. Allerdings bin ich nicht verantwortlich für Lizenzprobleme, falls es welche gibt.

18voto

lpiepiora Punkte 13491

Mit Java7+ kann dies erreicht werden durch das Erstellen von FileSystem und dann mit walkFileTree um Dateien rekursiv zu kopieren.

public void copyFromJar(String source, final Path target) throws URISyntaxException, IOException {
    URI resource = getClass().getResource("").toURI();
    FileSystem fileSystem = FileSystems.newFileSystem(
            resource,
            Collections.<String, String>emptyMap()
    );

    final Path jarPath = fileSystem.getPath(source);

    Files.walkFileTree(jarPath, new SimpleFileVisitor<Path>() {

        private Path currentTarget;

        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            currentTarget = target.resolve(jarPath.relativize(dir).toString());
            Files.createDirectories(currentTarget);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            Files.copy(file, target.resolve(jarPath.relativize(file).toString()), StandardCopyOption.REPLACE_EXISTING);
            return FileVisitResult.CONTINUE;
        }

    });
}

Die Methode kann wie folgt verwendet werden:

copyFromJar("/path/to/the/template/in/jar", Paths.get("/tmp/from-jar"))

15voto

Vinay Sajip Punkte 89444

Ich halte Ihren Ansatz, eine Zip-Datei zu verwenden, für sinnvoll. Vermutlich werden Sie eine getResourceAsStream um auf die Interna des Zip-Archivs zuzugreifen, das logischerweise wie ein Verzeichnisbaum aussehen wird.

Ein Skelettansatz:

InputStream is = getClass().getResourceAsStream("my_embedded_file.zip");
ZipInputStream zis = new ZipInputStream(is);
ZipEntry entry;

while ((entry = zis.getNextEntry()) != null) {
    // do something with the entry - for example, extract the data 
}

8voto

nivekastoreth Punkte 1357

Die Idee, die zuvor gepostete ZIP-Datei-Methode zu verwenden, gefiel mir nicht, also habe ich mir Folgendes ausgedacht.

public void copyResourcesRecursively(URL originUrl, File destination) throws Exception {
    URLConnection urlConnection = originUrl.openConnection();
    if (urlConnection instanceof JarURLConnection) {
        copyJarResourcesRecursively(destination, (JarURLConnection) urlConnection);
    } else if (urlConnection instanceof FileURLConnection) {
        FileUtils.copyFilesRecursively(new File(originUrl.getPath()), destination);
    } else {
        throw new Exception("URLConnection[" + urlConnection.getClass().getSimpleName() +
                "] is not a recognized/implemented connection type.");
    }
}

public void copyJarResourcesRecursively(File destination, JarURLConnection jarConnection ) throws IOException {
    JarFile jarFile = jarConnection.getJarFile();
    for (JarEntry entry : CollectionUtils.iterable(jarFile.entries())) {
        if (entry.getName().startsWith(jarConnection.getEntryName())) {
            String fileName = StringUtils.removeStart(entry.getName(), jarConnection.getEntryName());
            if (!entry.isDirectory()) {
                InputStream entryInputStream = null;
                try {
                    entryInputStream = jarFile.getInputStream(entry);
                    FileUtils.copyStream(entryInputStream, new File(destination, fileName));
                } finally {
                    FileUtils.safeClose(entryInputStream);
                }
            } else {
                FileUtils.ensureDirectoryExists(new File(destination, fileName));
            }
        }
    }
}

Beispiel Useage (kopiert alle Dateien aus der Klassenpfadressource "config" nach "${homeDirectory}/config":

File configHome = new File(homeDirectory, "config/");
//noinspection ResultOfMethodCallIgnored
configHome.mkdirs();
copyResourcesRecursively(super.getClass().getResource("/config"), configHome);

Dies sollte sowohl für das Kopieren von Flat Files als auch von Jar Files funktionieren.

Hinweis: Der obige Code verwendet einige benutzerdefinierte Utility-Klassen (FileUtils, CollectionUtils) sowie einige aus der Apache-Commons-Lang (StringUtils), aber die Funktionen sollten ziemlich eindeutig benannt werden.

6voto

Duc Loi Punkte 71

Die Antwort von lpiepiora, ist richtig! Aber es gibt ein kleines Problem, Die Quelle, sollte eine jar Url sein. Wenn der Quellpfad ein Pfad zu einem Dateisystem ist, dann wird der obige Code nicht richtig funktionieren. Um dieses Problem zu lösen, sollten Sie die ReferencePath, der Code, können Sie aus dem folgenden Link zu erhalten: Lesen aus dem Dateisystem über das FileSystem-Objekt Der neue Code von copyFromJar sollte so aussehen:

public class ResourcesUtils {
public static void copyFromJar(final String sourcePath, final Path target) throws URISyntaxException,
        IOException {
    final PathReference pathReference = PathReference.getPath(new URI(sourcePath));
    final Path jarPath = pathReference.getPath();

    Files.walkFileTree(jarPath, new SimpleFileVisitor<Path>() {

        private Path currentTarget;

        @Override
        public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
            currentTarget = target.resolve(jarPath.relativize(dir)
                    .toString());
            Files.createDirectories(currentTarget);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
            Files.copy(file, target.resolve(jarPath.relativize(file)
                    .toString()), StandardCopyOption.REPLACE_EXISTING);
            return FileVisitResult.CONTINUE;
        }

    });
}

public static void main(final String[] args) throws MalformedURLException, URISyntaxException, IOException {
    final String sourcePath = "jar:file:/c:/temp/example.jar!/src/main/resources";
    ResourcesUtils.copyFromJar(sourcePath, Paths.get("c:/temp/resources"));
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X