file.listFiles() NullPointerException on build jar - java

When I run my code on Intellij Idea it work perfectly but when I run my code on the .jar (so build) there is a NullPointerException. Did someone know why and how to fix this ?
File folder = new
File(Main.class.getClassLoader().getResource("assets/maps/").getPath());
System.out.println(folder);
System.out.println(folder.listFiles());
for (File file : folder.listFiles()) {
if(file.getName().endsWith(".btdm"))
maps.add(getMap(file));
}
console :
file:\E:\Programmation\BabyTD\out\artifacts\BabyTD_jar\BabyTD.jar!\assets\maps
null
Exception in thread "main" java.lang.NullPointerException
at fr.picearth.Main.getMaps(Main.java:51)
at fr.picearth.Main.main(Main.java:26)

If folder is not a folder or cannot be accessed for some reason (including the fact that java.io.File cannot open jar or other zip files like ordinary folders), then listFiles() will return null. You've already seen this in your print out. You have to check prior to iterating:
File[] files = folder.listFiles();
if (files != null)
for (File file : files)
if(file.getName().endsWith(".btdm"))
maps.add(getMap(file));
However, you probably want to work with java.util.zip.ZipFile instead

Assuming assets/maps/ folder is part of your jar file, then you won't be able to access like any other folder on your drive.
IDE consider it as folder/file on drive so it works with getResource.
What you could do is to use getResourceAsStream() method with the directory path, and the input Stream will have all the files name from that dir.
try getResourceAsStream inplace of getResource
String respath = "/path_to_file";
InputStream in = sample2.class.getResourceAsStream(respath);
if ( in == null ){
throw new Exception("resource not found: " + respath);
}
InputStreamReader inr = new InputStreamReader(in, "UTF-8");
int len;
char cbuf[] = new char[2048];
while ((len = inr.read(cbuf, 0, cbuf.length)) != -1) {
// do something with cbuf
}
EDIT 2 :
if you are using java 7+ then you can also use
private Path getFolderPath() throws URISyntaxException, IOException {
URI uri = getClass().getClassLoader().getResource("folder").toURI();
if ("jar".equals(uri.getScheme())) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
return fileSystem.getPath("path/to/folder/inside/jar");
} else {
return Paths.get(uri);
}
}

Related

Java 8: How to copy files written in a list to a TXT file from one directory to another directory?

I have a simple text file called small_reports.txt that looks like:
report_2021_05_02.csv
report_2021_05_05.csv
report_2021_06_08.csv
report_2021_06_25.csv
report_2021_07_02.csv
This reported is generated with my java code and takes in each of these files from the directory /work/dir1/reports and writes them into the file combined_reports.txt and then places the txt file back into /work/dir1/reports.
My question is, for each line in small_reports.txt, find that same file (line) in /work/dir1/reports and then COPY them to a new directory called /work/dir1/smallreports?
Using Java 8 & NIO (which is really helpful and good) I have tried:
Path source = Paths.get("/work/dir1/reports/combined_reports.txt");
Path target = Paths.get("/work/dir1/smallreports/", "combined_reports.txt");
if (Files.notExists(target) && target != null) {
Files.createDirectories(Paths.get(target.toString()));
}
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
But this is just copying the actual txt file combined_reports.txt into the new directory and not the contents inside like i thought it would.
final String SOURCE_DIR = "/tmp";
final String TARGET_DIR = "/tmp/root/delme";
List<String> csvFileNames = Files.readAllLines(FileSystems.getDefault().getPath("small_reports.txt"), Charset.forName("UTF-8"));
for (String csvFileName : csvFileNames) {
Path source = Paths.get(SOURCE_DIR, csvFileName);
Path target = Paths.get(TARGET_DIR, csvFileName);
if (Files.notExists(target) && target != null) {
Files.createDirectories(Paths.get(target.toString()));
}
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
}
Should do it for you. Obviously change the constants appropriately

Random file from a folder inside JAR

I want to get a random image from a specific folder in Java. The code does already work inside the Eclipse IDE, but not in my runnable JAR. Since images inside the JAR file are not files, the code below results in a NullPointerException, but I'm not sure how to "translate" the code so that it will work in a runnable JAR.
final File dir = new File("images/");
File[] files = dir.listFiles();
Random rand = new Random();
File file = files[rand.nextInt(files.length)];
If the given path is invalid then listFiles() method reutrns null value. So you have to handle it if the path is invalid. Check below code:
final File dir = new File("images/");
File[] files = dir.listFiles();
Random rand = new Random();
File file = null;
if (files != null) {
file = files[rand.nextInt(files.length)];
}
If the jar is to contain the images then (assuming a maven or gradle project) they should be in the resources directory (or a subdirectory thereof). These images are then indeed no 'Files' but 'Resources' and should be loaded using getClass().getResource(String name) or getClass.getResourceAsStream(String name).
You could create a text file listing the resource paths of the images. This would allow you to simply read all lines from that file and access the resource via Class.getResource.
You could even create such a list automatically. The following works for my project type in eclipse; some minor adjustments may be needed for your IDE.
private static void writeResourceCatalog(Path resourcePath, Path targetFile) throws IOException {
URI uri = resourcePath.toUri();
try (BufferedWriter writer = Files.newBufferedWriter(targetFile, StandardCharsets.UTF_8)) {
Files.list(resourcePath.resolve("images")).filter(Files::isRegularFile).forEach(p -> {
try {
writer.append('/').append(uri.relativize(p.toUri()).toString()).append('\n');
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
writeResourceCatalog(Paths.get("src", "main", "resources"), Paths.get("src", "main", "resources", "catalog.txt"));
After building the jar with the new file included you could simply list all the files as
List<URL> urls = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(WriteTest.class.getResourceAsStream("/catalog.txt"), StandardCharsets.UTF_8))) {
String s;
while ((s = reader.readLine()) != null) {
urls.add(SomeType.class.getResource(s));
}
}
It seem like a path Problem, maybe will work if tried absolute path for image directory or set maon directory for java configuration

Moving from one directory to another java [duplicate]

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

How to write the path of file in FileInputStream() where the file exits in a zip file then a jar file

C:/Data.zip/text.jar/a.xml is the location of a.xml so when I am using it like
FileInputStream fis = new FileInputStram("C:/Data.zip/text.jar/a.xml");
it gives me FileNotFoundException and also when I am using FileInputStream("/a.xml") throwing same FileNotFoundException.
You need to use a JarInputStream in top of the FileInoutStream pointing to the jar, not the xml. Then you need to find that xml file in the JarInoutStream and process it.
JarInputStream jarStream = new JarInputStream(new FileInputStream("your_jar_path"));
JarEntry entry;
while ((jarEntry = jarStream.getNextJarEntry()) != null) {
if (jarEntry.getName().equals("xmlfile_youlookfor")) {
doyourstuff
}
}
}
Remember to close stream.
Edit: I noticed now that you are talking about a jar inside a zip. But it doesn't change a lot the solution. Just open first the zip with a ZipFileStream and find the jar file inside in a similar way as the above code does with xml inside jar. Then just do the JarInputStream with the found entry inside the zip.
Edit2: Some sample code. Haven't tested it, but it should only contain minor typos (if any):
public void read() throws IOException {
ZipInputStream zipStream = null;
try {
zipStream = new ZipInputStream(new FileInputStream("C:/Data.zip"));
ZipEntry zipEntry;
boolean zipEntryFound = false;
while ((zipEntry = zipStream.getNextEntry()) != null) {
if (zipEntry.getName().equals("text.jar")) {
zipEntryFound=true;
break;
}
}
if (!zipEntryFound) {
return;
}
JarInputStream jarStream = new JarInputStream(zipStream);
JarEntry jarEntry;
boolean jarEntryFound = false;
while ((jarEntry = jarStream.getNextJarEntry()) != null) {
if (jarEntry.getName().equals("a.xml")) {
jarEntryFound = true;
break;
}
}
if (!jarEntryFound) {
return;
}
// now your jarStream is positioned on the a.xml file entry, just read
// the bytes from the stream. you know how many bytes from the
// jarEntry info
} catch (Exception e) {
if (zipStream != null) {
zipStream.close();
}
}
}
The JRE routinely accesses files in JAR, and you can use that capability through ClassLoader. However, accessing a file inside a JAR inside a ZIP is beyond its capabilities. There may be a custom framework somewhere that does that, but I haven't heard of it.
The solution you showed should work in general, assuming you know where the JAR file is. If the JAR is on the classpath, then
this.getClass().getClassLoader().getResourceAsStream(String name)
The "name" is the path to the file, starting from the root of the classpath. The path should start with a "/" or it will be relative.

How do I move a file from one location to another in Java?

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

Categories