Skip to content

Instantly share code, notes, and snippets.

@EvgeniGordeev
Created January 27, 2021 04:20
Show Gist options
  • Save EvgeniGordeev/90b04409acedb6627751f96f6743253d to your computer and use it in GitHub Desktop.
Save EvgeniGordeev/90b04409acedb6627751f96f6743253d to your computer and use it in GitHub Desktop.
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.ProviderMismatchException;
import java.util.Collections;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Stream;
/**
* Recursive copy of directory from a folder on the file system or inside a jar to another folder.
*/
public class Copy {
public static void main(String[] args) throws MalformedURLException {
if (args == null || args.length < 2) {
System.out.println("Usage: CopyDir <dir_from> <dir_to>, dir_from may start with file: or jar:file:");
return;
}
String from = args[0];
if (!from.startsWith("file:") || !from.startsWith("jar:")) {
from = "file:" + from;
}
cp(new URL(from), Paths.get(args[1]));
}
@FunctionalInterface
interface TriFunction<A, B, C, R> {
R apply(A a, B b, C c);
}
/**
* Copy a file or a directory recursively from the file system or within a jar file.
*
* @param fromUrl URL to a directory or file to copy
* @param toPath where copy the target to
* @return true if operation successful
*/
public static boolean cp(URL fromUrl, Path toPath) {
if (fromUrl == null) {
return false;
}
try {
final Path from;
TriFunction<Path, Path, Path, Path> getDest;
URI fromUri = fromUrl.toURI();
switch (fromUrl.getProtocol()) {
case "file":
Path path = Paths.get(fromUri);
if (!Files.exists(path)) {
return false;
}
from = path.toRealPath();
getDest = (source, toDir, fromDir) -> toDir.resolve(fromDir.relativize(source));
break;
case "jar":
final FileSystem fileSystem = FileSystems.newFileSystem(fromUri, Collections.emptyMap());
final String wholePath = fromUri.toString();
final String jarFile = fileSystem.toString();
if (!Files.exists(Paths.get(jarFile))) {
return false;
}
String jarName = Paths.get(fileSystem.toString()).getFileName().toString();
String pathInJar = wholePath.substring(wholePath.indexOf(jarName + "!") + jarName.length() + 1 /* taking ! into account */);
JarFile jar = new JarFile(jarFile);
JarEntry entry = jar.getJarEntry(pathInJar.startsWith("/") ? pathInJar.substring(1) : pathInJar);
if (entry == null) {
return false;
}
from = fileSystem.getPath(pathInJar);
getDest = (source, toDir, fromDir) -> toDir.resolve(fromDir.relativize(fileSystem.getPath(source.toString())).toString());
break;
default:
System.out.printf("Unknown file system - %s%n", fromUrl.getProtocol());
return false;
}
// mkdir -p
if (!Files.exists(toPath)) {
Files.createDirectories(toPath);
}
Path to = toPath.toRealPath();
System.out.printf("Copying %s to %s%n", fromUrl, to);
try (Stream<Path> stream = Files.walk(from)) {
stream.forEach(source -> copy(source, getDest.apply(source, to, from)));
}
} catch (IOException | URISyntaxException | ProviderMismatchException e) {
System.out.println(e.getMessage());
return false;
}
return true;
}
private static void copy(Path source, Path dest) {
try {
Files.copy(source, dest, REPLACE_EXISTING);
} catch (IOException e) {
throw new RuntimeException("Couldn't copy", e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment