2012-04-25 15 views
33

Chcę skopiować plik ze słoika. Plik, który kopiuję, zostanie skopiowany poza katalog roboczy. Zrobiłem kilka testów i wszystkie metody, które wypróbuję, kończą się plikami 0 bajtów.Jak skopiować plik wewnątrz słoika na zewnątrz słoika?

EDIT: Chcę, aby kopiowanie pliku odbywało się za pomocą programu, a nie ręcznie.

+2

pokazać nam to, czego próbowałem. –

+0

Czy musisz to programować? Jeśli nie, możesz zmienić nazwę pliku 'Foo.jar' na' Foo.zip' i rozpakować go normalnie. – Jeffrey

+0

@Jeffrey Tak, robię – jtl999

Odpowiedz

41

Przede wszystkim chcę powiedzieć, że niektóre z zamieszczonych wcześniej odpowiedzi są całkowicie poprawne, ale chcę je podać, ponieważ czasami nie możemy korzystać z bibliotek open source na licencji GPL, lub dlatego, że jesteśmy zbyt leniwi, aby pobrać słoik XD lub jakikolwiek twój powód jest tutaj, to samodzielne rozwiązanie.

Poniższa funkcja kopiowania zasobów obok pliku JAR:

/** 
    * Export a resource embedded into a Jar file to the local file path. 
    * 
    * @param resourceName ie.: "/SmartLibrary.dll" 
    * @return The path to the exported resource 
    * @throws Exception 
    */ 
    static public String ExportResource(String resourceName) throws Exception { 
     InputStream stream = null; 
     OutputStream resStreamOut = null; 
     String jarFolder; 
     try { 
      stream = ExecutingClass.class.getResourceAsStream(resourceName);//note that each/is a directory down in the "jar tree" been the jar the root of the tree 
      if(stream == null) { 
       throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file."); 
      } 

      int readBytes; 
      byte[] buffer = new byte[4096]; 
      jarFolder = new File(ExecutingClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile().getPath().replace('\\', '/'); 
      resStreamOut = new FileOutputStream(jarFolder + resourceName); 
      while ((readBytes = stream.read(buffer)) > 0) { 
       resStreamOut.write(buffer, 0, readBytes); 
      } 
     } catch (Exception ex) { 
      throw ex; 
     } finally { 
      stream.close(); 
      resStreamOut.close(); 
     } 

     return jarFolder + resourceName; 
    } 

wystarczy zmienić ExecutingClass nazwy swojej klasie, i nazywają to tak:

String fullPath = ExportResource("/myresource.ext"); 
+1

Zabawne jest to, że musiałem wykonać to dokładne zadanie dla innego programu, nad którym pracowałem. To działa. Dzięki! – jtl999

+0

Powodzenia! Cieszę się, że mogę Ci pomóc! – Ordiel

+1

Dzięki Ordiel, ale dlaczego ustawiamy bufor szie jako 4 bajty? – hackjutsu

0

Słoik to tylko plik zip. Rozpakuj go (używając dowolnej metody, z którą czujesz się komfortowo) i normalnie skopiuj plik.

-1
${JAVA_HOME}/bin/jar -cvf /path/to.jar 
26

Biorąc pod uwagę Twój komentarz pliki o 0-bajtowych, muszę założyć, że próbujesz to zrobić programowo, a biorąc pod uwagę tagi, że robisz to w Javie. Jeśli to prawda, po prostu użyj Class.getResource(), aby uzyskać adres URL wskazujący plik w Twoim pliku JAR, a następnie Apache Commons IO FileUtils.copyURLToFile(), aby skopiować go do systemu plików. Np .:

URL inputUrl = getClass().getResource("/absolute/path/of/source/in/jar/file"); 
File dest = new File("/path/to/destination/file"); 
FileUtils.copyURLToFile(inputUrl, dest); 

Najprawdopodobniej problem z jakiegokolwiek kodu masz teraz jest to, że jesteś (prawidłowo) z użyciem buforowanego strumienia wyjściowego do zapisu pliku, ale (niesłusznie) w przypadku braku aby go zamknąć.

Aha, należy edytować swoje pytanie do wyjaśnienia dokładnie jak chcesz to (programowo, NOT, język, ...) zrobić

+0

Ta odpowiedź * zakłada *, że plik JAR znajduje się w ścieżce klasy. Tak być może nie jest. I nawet jeśli tak jest, może być inny plik JAR w ścieżce klasy, który ukrywa określony plik, który OP próbuje wyodrębnić. –

+0

To prawda, ale jeśli moje założenia są poprawne, wydaje mi się, że jest to najbardziej prawdopodobny scenariusz. Jeśli się mylę, są tu inne odpowiedzi, które się tym zajmą. –

+0

Dobra interpretacja pytania przed edycją. –

1

użyć klasy JarInputStream:

// assuming you already have an InputStream to the jar file.. 
JarInputStream jis = new JarInputStream(is); 
// get the first entry 
JarEntry entry = jis.getNextEntry(); 
// we will loop through all the entries in the jar file 
while (entry != null) { 
    // test the entry.getName() against whatever you are looking for, etc 
    if (matches) { 
    // read from the JarInputStream until the read method returns -1 
    // ... 
    // do what ever you want with the read output 
    // ... 
    // if you only care about one file, break here 
    } 
    // get the next entry 
    entry = jis.getNextEntry(); 
} 
jis.close(); 

Zobacz także: JarEntry

9

Java 8 (właściwie FileSystem jest tam od 1.7) pochodzi z fajnymi nowymi klasami/metodami radzenia sobie z tym.Jak ktoś już wspomniał, że JAR jest w zasadzie plik ZIP, można użyć

final URI jarFileUril = URI.create("jar:file:" + file.toURI().getPath()); 
final FileSystem fs = FileSystems.newFileSystem(jarFileUri, env); 

(Zobacz Zip File)

Wtedy można skorzystać z jednej z dogodnych metod, takich jak:

fs.getPath("filename"); 

wtedy może używać plików Klasa

try (final Stream<Path> sources = Files.walk(from)) { 
    sources.forEach(src -> { 
     final Path dest = to.resolve(from.relativize(src).toString()); 
     try { 
      if (Files.isDirectory(from)) { 
       if (Files.notExists(to)) { 
        log.trace("Creating directory {}", to); 
        Files.createDirectories(to); 
       } 
      } else { 
       log.trace("Extracting file {} to {}", from, to); 
       Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING); 
      } 
     } catch (IOException e) { 
      throw new RuntimeException("Failed to unzip file.", e); 
     } 
    }); 
} 

Uwaga: ja tr IED że rozpakować pliki JAR do testowania

+0

Bardzo interesujące, przyjrzymy się temu przyszłym projektom :) – jtl999

+0

Dodałem go tutaj, tylko dla wszystkich, którzy mogą w tym uczestniczyć i dlaczego nie stosować nowego/krótszego podejścia. – Lukino

+0

'jar: file:" + file.toURI(). GetPath() 'wygląda nieco bezsensownie. Dlaczego nie po prostu '' jar: "+ file.toURI()' 'przy okazji, to' toURI() 'zamiast' toUri() ' – Holger

0

Aby skopiować plik ze słoika, na zewnątrz, trzeba użyć następujące podejście:

  1. uzyskać InputStream do pliku wewnątrz pliku jar przy użyciu getResourceAsStream()
  2. Otwieramy nasz plik celu przy użyciu FileOutputStream
  3. Kopiujemy bajtów z wejścia do strumienia wyjściowego
  4. zamkniemy strumieni w celu zapobieżenia wyciekom zasobów

przykład kodu, który zawiera również zmienną nie zastąpią istniejące wartości:

public File saveResource(String name) throws IOException { 
    return saveResource(name, true); 
} 

public File saveResource(String name, boolean replace) throws IOException { 
    return saveResource(new File("."), name, replace) 
} 

public File saveResource(File outputDirectory, String name) throws IOException { 
    return saveResource(outputDirectory, name, true); 
} 

public File saveResource(File outputDirectory, String name, boolean replace) 
     throws IOException { 
    File out = new File(outputDirectory, name); 
    if (!replace && out.exists()) 
     return out; 
    // Step 1: 
    InputStream resource = this.getClass().getResourceAsStream(name); 
    if (resource == null) 
     throw new FileNotFoundException(name + " (resource not found)"); 
    // Step 2 and automatic step 4 
    try(InputStream in = resource; 
     OutputStream writer = new BufferedOutputStream(
      new FileOutputStream(out))) { 
     // Step 3 
     byte[] buffer = new byte[1024 * 4]; 
     int length; 
     while((length = in.read(buffer)) >= 0) { 
      writer.write(buffer, 0, length); 
     } 
    } 
    return out; 
} 
4

Szybszy sposób to zrobić z Java 7+ plus kod aby otrzymać aktualny katalog:

/** 
    * Copy a file from source to destination. 
    * 
    * @param source 
    *  the source 
    * @param destination 
    *  the destination 
    * @return True if succeeded , False if not 
    */ 
    public static boolean copy(InputStream source , String destination) { 
     boolean succeess = true; 

     System.out.println("Copying ->" + source + "\n\tto ->" + destination); 

     try { 
      Files.copy(source, Paths.get(destination), StandardCopyOption.REPLACE_EXISTING); 
     } catch (IOException ex) { 
      logger.log(Level.WARNING, "", ex); 
      succeess = false; 
     } 

     return succeess; 

    } 

Testowanie go (icon.png to obraz wewnątrz obrazu pakietu aplikacji):

copy(getClass().getResourceAsStream("/image/icon.png"),getBasePathForClass(Main.class)+"icon.png"); 

O linii kodu (getBasePathForClass(Main.class)): -> Sprawdź odpowiedź Dodałem tutaj :) ->Getting the Current Working Directory in Java

Powiązane problemy