public static void build(File destination, String replacement, byte replacementData[])
throws IOException
{
FileUtils.copyFile(JAR_FILE, destination);
java.nio.file.Path destinationPath = destination.toPath();
ByteArrayInputStream in = new ByteArrayInputStream(replacementData);
FileSystem fileSystem = FileSystems.newFileSystem
//FileSystem fileSystem = FileSystems.newFileSystem(destinationPath, (ClassLoader)null);
java.nio.file.Path replacementPath = fileSystem.getPath(replacement, new String[0]);
Files.copy(in, replacementPath, new CopyOption[] {
StandardCopyOption.REPLACE_EXISTING
});
fileSystem.close();
in.close();
}
The message box said newFileSystem is ambiguous
This line not show error, but compile, but not work
FileSystem fileSystem = FileSystems.newFileSystem(destinationPath, (ClassLoader)null);
This line not show error, but compile, but not work
FileSystem fileSystem = FileSystems.newFileSystem(destinationPath, null, null);
This Line show error and not compile and show this message
reference to newFileSystem is ambiguous both method newFileSystem(Path,ClassLoader) in FileSystems and method newFileSystem(Path,Map<String,?>)in FileSystems match
FileSystem fileSystem = FileSystems.newFileSystem(destinationPath, null);
Related
Can a java.nio.file.FileSystem be created for a zip file that's inside a zip file?
If so, what does the URI look like?
If not, I'm presuming I'll have to fall back to using ZipInputStream.
I'm trying to recurse into the method below. Current implementation creates a URI "jar:jar:...". I know that's wrong (and a potentially traumatic reminder of a movie character). What should it be?
private static void traverseZip(Path zipFile ) {
// Example: URI uri = URI.create("jar:file:/codeSamples/zipfs/zipfstest.zip");
String sURI = "jar:" + zipFile.toUri().toString();
URI uri = URI.create(sURI);
Map<String, String> env = new HashMap<>();
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
Iterable<Path> rootDirs = fs.getRootDirectories();
for (Path rootDir : rootDirs) {
traverseDirectory(rootDir ); // Recurses back into this method for ZIP files
}
} catch (IOException e) {
System.err.println(e);
}
}
You can use FileSystem.getPath to return a Path suitable for use with another FileSystems.newFileSystem call which opens the nested ZIP/archive.
For example this code opens a war file and reads the contents of the inner jar file:
Path war = Path.of("webapps.war");
String pathInWar = "WEB-INF/lib/some.jar";
try (FileSystem fs = FileSystems.newFileSystem(war)) {
Path jar = fs.getPath(pathInWar);
try (FileSystem inner = FileSystems.newFileSystem(jar)) {
for (Path root : inner.getRootDirectories()) {
try (Stream<Path> stream = Files.find(root, Integer.MAX_VALUE, (p,a) -> true)) {
stream.forEach(System.out::println);
}
}
}
}
Note also that you code can pass in zipFile without changing to URI:
try (FileSystem fs = FileSystems.newFileSystem(zipFile, env)) {
I am getting fileNotFoundException in the mentioned line below. Earlier in Hadoop 1 this was functional. But now it throws a FileNotFoundException
Path localManifestFolder;
Path localManifestPath = new Path("hdfs:///WordCount/write/manifest");
PrintWriter pw = null;
FileSystem fs = null;
try {
URI localHDFSManifestUri = new URI("
hdfs:///WordCount/write");
fs = FileSystem.get(localHDFSManifestUri, conf);
localManifestFolder = new Path("hdfs:///WordCount/write");
FileStatus[] listOfFiles = fs.listStatus(localManifestFolder); // Getting Error in this line
} catch (FileNotFoundException ex) {
throw ex;
}
Exception :
java.io.FileNotFoundException: File hdfs:/WordCount/write does not exist.
Please tell me why such thing is happening
If you do not have your core-site.xml on the classpath, then you need to specify the HDFS location (otherwise defaults to local filesystem)
For example
hdfs://namenode.fqdn:8020/WordCount
How do you move a file from one location to another? When I run my program any file created in that location automatically moves to the specified location. How do I know which file is moved?
myFile.renameTo(new File("/the/new/place/newName.file"));
File#renameTo does that (it can not only rename, but also move between directories, at least on the same file system).
Renames the file denoted by this abstract pathname.
Many aspects of the behavior of this method are inherently platform-dependent: The rename operation might not be able to move a file from one filesystem to another, it might not be atomic, and it might not succeed if a file with the destination abstract pathname already exists. The return value should always be checked to make sure that the rename operation was successful.
If you need a more comprehensive solution (such as wanting to move the file between disks), look at Apache Commons FileUtils#moveFile
With Java 7 or newer you can use Files.move(from, to, CopyOption... options).
E.g.
Files.move(Paths.get("/foo.txt"), Paths.get("bar.txt"), StandardCopyOption.REPLACE_EXISTING);
See the Files documentation for more details
Java 6
public boolean moveFile(String sourcePath, String targetPath) {
File fileToMove = new File(sourcePath);
return fileToMove.renameTo(new File(targetPath));
}
Java 7 (Using NIO)
public boolean moveFile(String sourcePath, String targetPath) {
boolean fileMoved = true;
try {
Files.move(Paths.get(sourcePath), Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
fileMoved = false;
e.printStackTrace();
}
return fileMoved;
}
File.renameTo from Java IO can be used to move a file in Java. Also see this SO question.
To move a file you could also use Jakarta Commons IOs FileUtils.moveFile
On error it throws an IOException, so when no exception is thrown you know that that the file was moved.
Just add the source and destination folder paths.
It will move all the files and folder from source folder to
destination folder.
File destinationFolder = new File("");
File sourceFolder = new File("");
if (!destinationFolder.exists())
{
destinationFolder.mkdirs();
}
// Check weather source exists and it is folder.
if (sourceFolder.exists() && sourceFolder.isDirectory())
{
// Get list of the files and iterate over them
File[] listOfFiles = sourceFolder.listFiles();
if (listOfFiles != null)
{
for (File child : listOfFiles )
{
// Move files to destination folder
child.renameTo(new File(destinationFolder + "\\" + child.getName()));
}
// Add if you want to delete the source folder
sourceFolder.delete();
}
}
else
{
System.out.println(sourceFolder + " Folder does not exists");
}
Files.move(source, target, REPLACE_EXISTING);
You can use the Files object
Read more about Files
You could execute an external tool for that task (like copy in windows environments) but, to keep the code portable, the general approach is to:
read the source file into memory
write the content to a file at the new location
delete the source file
File#renameTo will work as long as source and target location are on the same volume. Personally I'd avoid using it to move files to different folders.
Try this :-
boolean success = file.renameTo(new File(Destdir, file.getName()));
Wrote this method to do this very thing on my own project only with the replace file if existing logic in it.
// we use the older file i/o operations for this rather than the newer jdk7+ Files.move() operation
private boolean moveFileToDirectory(File sourceFile, String targetPath) {
File tDir = new File(targetPath);
if (tDir.exists()) {
String newFilePath = targetPath+File.separator+sourceFile.getName();
File movedFile = new File(newFilePath);
if (movedFile.exists())
movedFile.delete();
return sourceFile.renameTo(new File(newFilePath));
} else {
LOG.warn("unable to move file "+sourceFile.getName()+" to directory "+targetPath+" -> target directory does not exist");
return false;
}
}
Please try this.
private boolean filemovetoanotherfolder(String sourcefolder, String destinationfolder, String filename) {
boolean ismove = false;
InputStream inStream = null;
OutputStream outStream = null;
try {
File afile = new File(sourcefolder + filename);
File bfile = new File(destinationfolder + filename);
inStream = new FileInputStream(afile);
outStream = new FileOutputStream(bfile);
byte[] buffer = new byte[1024 * 4];
int length;
// copy the file content in bytes
while ((length = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, length);
}
// delete the original file
afile.delete();
ismove = true;
System.out.println("File is copied successful!");
} catch (IOException e) {
e.printStackTrace();
}finally{
inStream.close();
outStream.close();
}
return ismove;
}
I've followed what this page has told me but I can't get it to work. I want it so that in my test.zip a folder called "new" will be in there. Whenever I run the code below it gives a FileAlreadyExistsException and only creates an empty zip file.
Map<String, String> env = new HashMap<>();
env.put("create", "true");
Path path = Paths.get("test.zip");
URI uri = URI.create("jar:" + path.toUri());
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
Path nf = fs.getPath("new/");
Files.createDirectory(path);
} catch (IOException e) {
e.printStackTrace();
}
Because Files.createDirectory() states in the javadoc
throws FileAlreadyExistsException - if dir exists but is not a
directory (optional specific exception)
you need to check if the folder already exits:
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
Path nf = fs.getPath("new");
if (Files.notExists(nf)) {
Files.createDirectory(nf);
}
}
Have you tried java.util.zip.ZipEntry ?
FileOutputStream f = new FileOutputStream("test.zip");
ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(f));
zip.putNextEntry(new ZipEntry("new/"));
Is there an API to get a classpath resource (e.g. what I'd get from Class.getResource(String)) as a java.nio.file.Path? Ideally, I'd like to use the fancy new Path APIs with classpath resources.
This one works for me:
return Path.of(ClassLoader.getSystemResource(resourceName).toURI());
Guessing that what you want to do, is call Files.lines(...) on a resource that comes from the classpath - possibly from within a jar.
Since Oracle convoluted the notion of when a Path is a Path by not making getResource return a usable path if it resides in a jar file, what you need to do is something like this:
Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();
The most general solution is as follows:
interface IOConsumer<T> {
void accept(T t) throws IOException;
}
public static void processRessource(URI uri, IOConsumer<Path> action) throws IOException{
try {
Path p=Paths.get(uri);
action.accept(p);
}
catch(FileSystemNotFoundException ex) {
try(FileSystem fs = FileSystems.newFileSystem(
uri, Collections.<String,Object>emptyMap())) {
Path p = fs.provider().getPath(uri);
action.accept(p);
}
}
}
The main obstacle is to deal with the two possibilities, either, having an existing filesystem that we should use, but not close (like with file URIs or the Java 9’s module storage), or having to open and thus safely close the filesystem ourselves (like zip/jar files).
Therefore, the solution above encapsulates the actual action in an interface, handles both cases, safely closing afterwards in the second case, and works from Java 7 to Java 18. It probes whether there is already an open filesystem before opening a new one, so it also works in the case that another component of your application has already opened a filesystem for the same zip/jar file.
It can be used in all Java versions named above, e.g. to list the contents of a package (java.lang in the example) as Paths, like this:
processRessource(Object.class.getResource("Object.class").toURI(),new IOConsumer<Path>(){
public void accept(Path path) throws IOException {
try(DirectoryStream<Path> ds = Files.newDirectoryStream(path.getParent())) {
for(Path p: ds)
System.out.println(p);
}
}
});
With Java 8 or newer, you can use lambda expressions or method references to represent the actual action, e.g.
processRessource(Object.class.getResource("Object.class").toURI(), path -> {
try(Stream<Path> stream = Files.list(path.getParent())) {
stream.forEach(System.out::println);
}
});
to do the same.
The final release of Java 9’s module system has broken the above code example. The Java versions from 9 to 12 inconsistently return the path /java.base/java/lang/Object.class for Paths.get(Object.class.getResource("Object.class")) whereas it should be /modules/java.base/java/lang/Object.class. This can be fixed by prepending the missing /modules/ when the parent path is reported as non-existent:
processRessource(Object.class.getResource("Object.class").toURI(), path -> {
Path p = path.getParent();
if(!Files.exists(p))
p = p.resolve("/modules").resolve(p.getRoot().relativize(p));
try(Stream<Path> stream = Files.list(p)) {
stream.forEach(System.out::println);
}
});
Then, it will again work with all versions and storage methods. Starting with JDK 13, this work-around is not necessary anymore.
It turns out you can do this, with the help of the built-in Zip File System provider. However, passing a resource URI directly to Paths.get won't work; instead, one must first create a zip filesystem for the jar URI without the entry name, then refer to the entry in that filesystem:
static Path resourceToPath(URL resource)
throws IOException,
URISyntaxException {
Objects.requireNonNull(resource, "Resource URL cannot be null");
URI uri = resource.toURI();
String scheme = uri.getScheme();
if (scheme.equals("file")) {
return Paths.get(uri);
}
if (!scheme.equals("jar")) {
throw new IllegalArgumentException("Cannot convert to Path: " + uri);
}
String s = uri.toString();
int separator = s.indexOf("!/");
String entryName = s.substring(separator + 2);
URI fileURI = URI.create(s.substring(0, separator));
FileSystem fs = FileSystems.newFileSystem(fileURI,
Collections.<String, Object>emptyMap());
return fs.getPath(entryName);
}
Update:
It’s been rightly pointed out that the above code contains a resource leak, since the code opens a new FileSystem object but never closes it. The best approach is to pass a Consumer-like worker object, much like how Holger’s answer does it. Open the ZipFS FileSystem just long enough for the worker to do whatever it needs to do with the Path (as long as the worker doesn’t try to store the Path object for later use), then close the FileSystem.
I wrote a small helper method to read Paths from your class resources. It is quite handy to use as it only needs a reference of the class you have stored your resources as well as the name of the resource itself.
public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
URL url = resourceClass.getResource(resourceName);
return Paths.get(url.toURI());
}
Read a File from resources folder using NIO, in java8
public static String read(String fileName) {
Path path;
StringBuilder data = new StringBuilder();
Stream<String> lines = null;
try {
path = Paths.get(Thread.currentThread().getContextClassLoader().getResource(fileName).toURI());
lines = Files.lines(path);
} catch (URISyntaxException | IOException e) {
logger.error("Error in reading propertied file " + e);
throw new RuntimeException(e);
}
lines.forEach(line -> data.append(line));
lines.close();
return data.toString();
}
You can not create URI from resources inside of the jar file. You can simply write it to the temp file and then use it (java8):
Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);
You need to define the Filesystem to read resource from jar file as mentioned in https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html. I success to read resource from jar file with below codes:
Map<String, Object> env = new HashMap<>();
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
Path path = fs.getPath("/path/myResource");
try (Stream<String> lines = Files.lines(path)) {
....
}
}