web-dev-qa-db-fra.com

Comment copier un fichier à l'intérieur du bocal en dehors du bocal?

Je veux copier un fichier d'un pot. Le fichier que je copie va être copié en dehors du répertoire de travail. J'ai fait des tests et toutes les méthodes que j'ai essayées se retrouvent avec des fichiers à 0 octets.

EDIT: Je veux que la copie du fichier soit faite via un programme, pas manuellement.

38
jtl999

Tout d’abord, je tiens à dire que certaines réponses publiées précédemment sont tout à fait correctes, mais je tiens à donner la mienne, car nous ne pouvons parfois pas utiliser de bibliothèques open source sous GPL, ou parce que nous sommes trop paresseux pour télécharger le fichier jar XD ou quoi quelle que soit votre raison, voici une solution autonome.

La fonction ci-dessous copie la ressource à côté du fichier 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;
    }

Changez simplement ExecutingClass avec le nom de votre classe et appelez-le comme ceci:

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

Edit for Java 7+ (pour votre commodité)

Comme répondu par GOXR3PLUS et noté par Andy Thomas vous pouvez y parvenir avec:

Files.copy( InputStream in, Path target, CopyOption... options)

Voir réponse GOXR3PLUS pour plus de détails

47
Ordiel

Compte tenu de votre commentaire sur les fichiers de 0 octet, je suppose que vous essayez de le faire par programmation et, compte tenu de vos balises, que vous le faites en Java. Si cela est vrai, utilisez simplement Class.getResource () pour obtenir une URL pointant vers le fichier de votre fichier JAR, puis Apache Commons IO FileUtils.copyURLToFile () pour le copier dans le système de fichiers. Par exemple.:

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

Très probablement, le problème avec le code que vous avez maintenant est que vous utilisez (correctement) un flux de sortie en mémoire tampon pour écrire dans le fichier mais que vous échouez (à tort) pour le fermer.

Oh, et vous devriez modifier votre question pour clarifier exactement comment vous voulez le faire (par programmation, non, langue, ...)

33
Ryan Stewart

Java 8 (FileSystem est présent depuis la version 1.7) est livré avec quelques nouvelles classes/méthodes pour gérer cela. Comme quelqu'un a déjà mentionné que JAR est essentiellement un fichier Zip, vous pouvez utiliser

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

(Voir Fichier Zip )

Ensuite, vous pouvez utiliser l'une des méthodes pratiques comme:

fs.getPath("filename");

Ensuite, vous pouvez utiliser la classe Files

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);
       }
     });
}

Note: J'ai essayé de décompresser les fichiers JAR pour les tester

11
Lukino

Une façon plus rapide de le faire avec Java 7+, plus du code pour obtenir le répertoire actuel:

   /**
     * 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;

    }

Le tester (icon.png est une image dans l'image du package de l'application):

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

À propos de la ligne de code (getBasePathForClass(Main.class)): -> vérifiez la réponse que j’ai ajoutée ici :) -> Obtention du répertoire de travail actuel en Java

9
GOXR3PLUS

Utilisez le JarInputStream class:

// 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();

Voir aussi: JarEntry

1
jarrad

Solution robuste:

public static void copyResource(String res, String dest, Class c) throws IOException {
    InputStream src = c.getResourceAsStream(res);
    Files.copy(src, Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
}

Vous pouvez l'utiliser comme ceci:

File tempFileGdalZip = File.createTempFile("temp_gdal", ".Zip");
copyResource("/gdal.Zip", tempFileGdalZip.getAbsolutePath(), this.getClass());
0
zoran

Pour copier un fichier de votre pot vers l'extérieur, vous devez utiliser l'approche suivante:

  1. Obtenez une InputStream dans le fichier à l'intérieur de votre fichier jar en utilisant getResourceAsStream()
  2. Nous ouvrons notre fichier cible en utilisant une FileOutputStream
  3. Nous copions des octets de l'entrée au flux de sortie
  4. Nous fermons nos flux pour éviter les fuites de ressources

Exemple de code contenant également une variable pour ne pas remplacer les valeurs existantes:

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;
}
0
Ferrybig