I am trying to lay down some core files in a dev-test-prod setup. Basically if the file is newer it needs to be copied to the next level as part of the QA process.
I am using Java 8 so I decided to try the NIO Files/Path apis for the first time. I am creaky old, having been programming for 48 years and have used almost exclusively Java since early 1996, and every release since prerelease, so this NIO "enhancement" should not be too hard for me to assimilate, but . . .
FileSystem fs = FileSystems.getDefault();
Path in = fs.getPath(fromFileName);
Path out = fs.getPath(toFileName);
if (Files.exists(out)) {
FileTime inTime = Files.getLastModifiedTime(in);
FileTime outTime = Files.getLastModifiedTime(out);
if (0 > outTime.compareTo(inTime)) {
Files.copy(in, out, StandardCopyOption.REPLACE_EXISTING);
}
} else {
Files.createFile(out);
Files.copy(in, out);
}
I initially just tried Files.copy() without Files.createFile() and got a NoSuchFileException on the copy() call.
I looked a several StackOverflow posts which referred to this, one of which stated authoritatively that copy() will fail if the destination file does not already exist. For the life of me I cannot understand why the designers thought this was a good idea, but so be it. I accordingly added the createFile() call as above (having read the API doc for Files which says that Files.createFile() "Creates a new and empty file, failing if the file already exists." When I ran it again I got exactly the same Exception, but on the createFile() instead of the copy(). Notice the path is inside my home directory on Windows, so no access denied issues should occur. Also NOTHING other than Eclipse containing this project is running on my PC at this time.
java.nio.file.NoSuchFileException: C:\Users\ChrisGage\myproject\site\ttws\css\core.css
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(Unknown Source)
at java.nio.file.Files.newByteChannel(Unknown Source)
at java.nio.file.Files.createFile(Unknown Source)
...
What am I doing wrong?
Files.copy() (and Files.move() for that matter) is "dumb"; it won't try and do any of the following:
copy entire directory hierarchies;
move entire directory hierarchies (if the source and target are on different filesystems);
create missing directories etc.
You need to do:
final Path tmp = out.getParent();
if (tmp != null) // null will be returned if the path has no parent
Files.createDirectories(tmp);
prior to copying the file.
Related
Asked this question, having already tried possible solutions in other questions here on stack but that didn't allow me to fix the problem.
As in the title, I have created a java utility with which I have to perform operations on text files, in particular I have to perform simple operations to move between directories, copy from one directory to another, etc.
To do this I have used the java libraries java.io.File and java.nio.*, And I have implemented two functions for now,copyFile(sourcePath, targetPath) and moveFile(sourcePath, targetPath).
To develop this I am using a mac, and the files are under the source path /Users/myname/Documents/myfolder/F24/archive/, and my target path is /Users/myname/Documents/myfolder/F24/target/.
But when I run my code I get a java.nio.file.NoSuchFileException: /Users/myname/Documents/myfolder/F24/archive
Having tried the other solutions here on stack and java documentation already I haven't been able to fix this yet ... I accept any advice or suggestion
Thank you all
my code:
// copyFile: funzione chiamata per copiare file
public static boolean copyFile(String sourcePath, String targetPath){
boolean fileCopied = true;
try{
Files.copy(Paths.get(sourcePath), Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING);
}catch(Exception e){
String sp = Paths.get(sourcePath)+"/";
fileCopied = false;
System.out.println("Non posso copiare i file dalla cartella "+sp+" nella cartella "+Paths.get(targetPath)+" ! \n");
e.printStackTrace();
}
return fileCopied;
}
Files.copy cannot copy entire directories. The first 'path' you pass to Files.copy must ALL:
Exist.
Be readable by the process that runs the JVM. This is non-trivial on a mac, which denies pretty much all disk rights to all apps by default until you give it access. This can be tricky for java apps. I'm not quite sure how you fix it (I did something on my mac to get rid of that, but I can't remember what - possibly out of the box java apps just get to read whatever they want and it's only actual mac apps that get pseudo-sandboxed. Point is, there's a chance it's mac's app access control denying it even if the unix file rights on this thing indicate you ought to be able to read it).
Be a plain old file and not a directory or whatnot.
Files.move can (usually - depends on impl and underlying OS) usually be done to directories, but not Files.copy. You're in a programming language, not a shell. If you want to copy entire directories, write code that does this.
Not sure whether my comment is understood though answered.
Ìn java SE target must not be the target directory. In other APIs of file copying
one can say COPY FILE TO DIRECTORY. In java not so; this was intentionally designed to remove one error cause.
That style would be:
Path source = Paths.get(sourcePath);
if (Files.isRegularFile(source)) {
Path target = Paths.get(targetPath);
Files.createDirectories(target);
if (Files.isDirectory(target)) {
target = Paths.get(targetPath, source.getFileName().toString());
// Or: target = target.resolve(source.getFileName().toString());
}
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
}
Better ensure when calling to use the full path.
I am currently trying to get a list of files in a directory.
When I try to get the filehandle for the directory it says that it is a file, but it isn't. When I then readString() from it, it returns the filenames of the files in it. This only happens in the IDE (Eclipse NEON.2), but when I export to JAR it crashes when I try to run.
How can I get LibGDX to recognise it as a directory and get all files in that directory. One last thing I have seen many anwers saying that list() doesn't work on desktop, but I have also read that it works. Can someone check if this is true or not.
public void loadEnemyBaseTypes(){
ArrayList<FileHandle> enemyBaseFiles = new ArrayList<FileHandle>();
FileHandle enemyBaseDirectory =
Gdx.files.internal("prototypes/enemybases");
System.out.println(enemyBaseDirectory.exists());
System.out.println(enemyBaseDirectory.isDirectory());
String[] fileNames = enemyBaseDirectory.readString().split("\n");
for(int i = 0; i < fileNames.length; i++)
System.out.println(fileNames[i]);
}
IDE Output:
true
false
base_0.enybse
base_1.enybse
base_2.enybse
base_3.enybse
base_4.enybse
base_5.enybse
Terminal Output:
true
false
Exception in thread "LWJGL Application" java.lang.NullPointerException
at java.io.FilterInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.Reader.read(Unknown Source)
at com.badlogic.gdx.files.FileHandle.readString(FileHandle.java:207)
at com.badlogic.gdx.files.FileHandle.readString(FileHandle.java:191)
at dev.thomaslienbacher.simplegame.controllers.EnemyManager.loadEnemyBaseTypes(EnemyManager.java:53)
at dev.thomaslienbacher.simplegame.controllers.EnemyManager.loadAssets(EnemyManager.java:33)
at dev.thomaslienbacher.simplegame.scene.GameScene.loadAssets(GameScene.java:62)
at dev.thomaslienbacher.simplegame.Game.update(Game.java:149)
at dev.thomaslienbacher.simplegame.Game.render(Game.java:134)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:223)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:124)
I created nested folder inside Assets list -> enemy then I keep three .png files inside enemy folder having name 1.png, 2.png and 3.png.
FileHandle enemyBaseDirectory = Gdx.files.internal("list/enemy");
System.out.println(enemyBaseDirectory.exists());
System.out.println(enemyBaseDirectory.isDirectory());
FileHandle allList[]=enemyBaseDirectory.list();
for (FileHandle fileHandle:allList)
System.out.println(fileHandle);
Output on IDE Run tab :
true true list/enemy/1.png list/enemy/2.png list/enemy/3.png
There is no any output on IDE local Terminal. My IDE is Intellij IDEA, hopefully result should be same on other IDE.
That is my expected output.
FileHandle's readString() reads the entire file into a string using the platform's default charset and if file handle represents a directory, doesn't exist, or could not be read then throw GdxRuntimeException.
The question started as - maven does not reach into jar for a folder bundle correctly, when running tests. It does work currectly when running some main() though.
The stack trace for running test (while building) looked like this:
Caused by: java.util.MissingResourceException: Can't find Not found profile: file:\C:\Users\Simon\.m2\repository\ario\TextProcessing\1.0.4-SNAPSHOT\TextProcessing-1.0.4-SNAPSHOT.jar!\lang bundle
at java.util.logging.Logger.setupResourceInfo(Logger.java:1942)
at java.util.logging.Logger.<init>(Logger.java:380)
at java.util.logging.LogManager.demandLogger(LogManager.java:554)
at java.util.logging.Logger.demandLogger(Logger.java:455)
at java.util.logging.Logger.getLogger(Logger.java:553)
at cz.techniserv.ario.tagger.TagDetect.setLangPath(TagDetect.java:126)
at cz.techniserv.ario.tagger.TagDetect.<init>(TagDetect.java:58)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
... 86 more
I triple checked - the lang folder is within the jar.
When running a main() within the module however, it does not try to reach into jar withing m2 repository, but will take the lang folder from within the opened dependency project. So it does not try to reach into a jar, just takes the data from project folder. This runs correctly.
Apparently, the File() constructor is unable to reach for the resource in the jar.
The code, that tries to reach into the jar is within a constructor. It looks like this:
this.path = this.getClass().getResource("/" + aLanguageDirectoryName).getPath();
and than there is a File constructor which takes this path.
In case of running the app it resolves to the project path. When it runs tests it will resolve to the jar within the m2 repository and tries to reach within the path that is in the exception:
file:\C:\Users\Simon\.m2\repository\ario\TextProcessing\1.0.4-SNAPSHOT\TextProcessing-1.0.4-SNAPSHOT.jar!\lang
What would you do? Would you copy the resource "lang" folder on some temporary path and provide the library with this new non-within-jar temporary path, so that it can open with the File() constructor? Or do you see another better way?
Ok, so what we did is that the data are ad hoc extracted to classpath and accessed.
The problem with this solution is that if you delete the files after usage, than you will always extract and delete data with each run - when this happens with every spring initialization of running tests this can happen extreme amount of times and take a lot of time. Leaving the data there however means that if the path is not absolute and out of the project trunk folder, SCM will pick it up unless you ignore it and commit the data which is not satisfying. Also they get packed into the jar upon build since they are on classpath which is another drawback. Yes, you can ignore with SCM and configure maven to exclude the folder, however some developers will forget (one already did) to ignore with SCM and it was commited.
We consider extracting to an absolute path which would not be on classpath a bad practice - firstly because you have no control on what system the projects run on so you cannot guess very well the absolute path - also it does not look pretty to throw data around your computer for bad design.
So I guess the best thing would be to push everyone to place the data on some place on their discs and set an environment variable which would be the same for everyone. This makes the project less portable, requires more configuration, but removes formerly mentioned problems.
I did not come up with anything better.
In case anyone would want to do the same thing, here is our code:
CodeSource src = this.getClass().getProtectionDomain().getCodeSource();
if (src == null) {
return null;
}
URL jarURL = src.getLocation();
try (JarFile jar = new JarFile(jarURL.getPath());) {
Enumeration<JarEntry> enumEntries = jar.entries();
while (enumEntries.hasMoreElements()) {
JarEntry fileFromJar = (JarEntry) enumEntries.nextElement();
File toBeCreatedFileLocally = new File(NAME_FOR_TEMPORARY_FOLDER_TO_HOLD_LANG_DATA_FROM_JAR + File.separator + fileFromJar.getName());
if (fileFromJar.isDirectory()) {
continue;
}
if (fileFromJar.getName().contains(aLanguageDirectoryName)) {
toBeCreatedFileLocally.getParentFile().mkdirs();
try (InputStream is = jar.getInputStream(fileFromJar); // get the input stream
FileOutputStream fos = new FileOutputStream(toBeCreatedFileLocally)) {
while (is.available() > 0) { // write contents of 'is' to 'fos'
fos.write(is.read());
}
}
}
}
} catch (IOException ex) {
Logger.getLogger(TagDetect.class.getName()).log(Level.SEVERE, null, ex);
}
This code is actually a modification of a different answer here https://stackoverflow.com/a/1529707/1920149 (beware, that answer has a bug, check comments - they rejected my edit)
My resources folder inside my jar includes a directory with several binary files. I am attempting to use this code to extract them:
try(InputStream is = ExternalHTMLThumbnail.class.getResourceAsStream("/wkhtmltoimage")) {
Files.copy(is, Paths.get("/home/dan/wkhtmltoimage");
}
This is throwing the error
java.nio.file.NoSuchFileException: /home/dan/wkhtmltoimage
Which comes from
if (errno() == UnixConstants.ENOENT)
return new NoSuchFileException(file, other, null);
in UnixException.java. Even though in Files.java the correct options are passed:
ostream = newOutputStream(target, StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE);
from Files.copy. Of course there's not! That's why I'm trying to make it. I don't yet understand Path and Files enough to do this right. What's the best way to extract the directory and all its contents?
Confused because the docs for Files.copy claims
By default, the copy fails if the target file already exists or is a symbolic link
(Apparently it fails if the target file doesn't exist as well?)
And lists the possible exceptions, and NoSuchFileException is not one of them.
If you're using Guava:
URL url = Resources.getResource(ExternalHTMLThumbnail.class, "wkhtmltoimage");
byte[] bytes = Resources.toByteArray(url);
Files.write(bytes, new File("/my/path/myFile"));
You could of course just chain that all into one line; I declared the variables to make it more readable.
The file that does not exist may actually be the directory you're trying to create the file in.
/home/dan/wkhtmltoimage
Does /home/dan exist? Probably not if you're on a Mac.
I have an app that serializes and reads/writes some custom objects in Java.
One of my clients has a particular file (only one) that is throwing a EOFException whenever the file is read into the ObjectInputStream constructor.
java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)
java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)
java.io.ObjectInputStream.readStreamHeader(Unknown Source)
java.io.ObjectInputStream.(Unknown Source)
EDIT: Sorry, my mistake. I forgot to mention that I am receiving the file through this code:
File folder = new File(path);
File[] files = folder.listFiles();
So, the File does exist as far as File#listFiles() is retrieving it.
So file in the code below is received from the loop:
for(File file : files)
Thus, the IOException shouldn't be from the file being missing (because why would listFiles() return it?).
END-EDIT
I figured this may be due to a glitch from a failed-partial-write of the object, so I added code to delete the problem file if there is a EOFException:
try (InputStream is = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(is);) {
// Do stuff...
} catch (IOException e) {
if(e instanceof EOFException) {
file.delete();
}
ErrorHandler.handleError(e);
}
Although this code executes successfully, it does not actually delete the file. (I still see the error in logs constantly). So, I opted to have my client manually search for and delete this file. He searched, found it, and deleted it. He confirmed to me that it successfully deleted the file. However, even after he manually deleted it, this error still pops up!
Although this is a Java program, my suspicion is this is a Windows file-system glitch so Java won't have much to do with this. Does anyone have experience with "ghost" files that seem to be there but aren't? Or that seem to get deleted but don't?
This is a confusing problem. Impossible for me to reproduce.
The file is empty, or doesn't contain a complete object stream header. In either event it is corrupt, and you should have detected that when you wrote it.
Probably you failed to close the ObjectOutputStream when you created the file.