Random file from a folder inside JAR - java

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

Related

NoSuchFileException while running jar file

When we convert code to jar file we get this error.
the code works with IDE
public String getwordleString() {
Path path = Paths.get("..\\termproject\\word_database.txt");
List<String> wordList = new ArrayList<>();
try {
wordList = Files.readAllLines(path);
} catch (IOException e) {
e.printStackTrace();
}
Random random = new Random();
int position = random.nextInt(wordList.size());
return wordList.get(position).trim().toUpperCase();
}
Error part is : https://ibb.co/z6vZLW5
Using Paths.get("..\\termproject\\word_database.txt") assumes that there is a directory "..\termproject\word_database.txt" starting at the current working directory. If the file does not exist, you will get an error.
If you want to wrap the directory with the JAR, you can set you "termproject" file as a src or class file. Then this will be accessible via getClass().getResourceAsStream("/word_database.txt"). Now you can read the text from the file with a BufferedReader like so:
BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/word_database.txt")));
String data = reader.lines().collect(Collectors.joining("\n"));

file.listFiles() NullPointerException on build jar

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

No Such File exception in Runnable Jar file

I am trying to create a runnable jar file. My project includes models.txt file. My project works perfectly in eclipse with no error but when exported to a runnable jar file, It doesn't work. I hereby attach the error and the piece of code where the file is been called.
public static HashMap<String, RenderModel> getModelList(String file) throws IOException {
List<String> data;
HashMap<String, RenderModel> namesToModels = new HashMap<String, RenderModel>();
if (file != null) {
data = Files.readAllLines(Paths.get(file), StandardCharsets.UTF_8);
} else {
String path = "models/models.txt";
data = Files.readAllLines(Paths.get(path), StandardCharsets.UTF_8);
}
Iterator<String> dataIterator = data.iterator();
while (dataIterator.hasNext()) {
String dataLine = dataIterator.next();
System.out.println(dataLine);
String[] line = dataLine.split("; ");
String key = line[0];
String valueObj = line[1];
String valueMtl = line[2];
float scale = Float.parseFloat((String) line[3]);
RenderModel v = new RenderModel(valueObj, valueMtl, scale);
namesToModels.put(key, v);
}
RenderModel v = new RenderModel("custom", "custom", 1.0f);
namesToModels.put("Choose Model from file", v);
return namesToModels;
}
Error Image:
If the files are in the Jar and you cannot read them, try accessing the files by doing:
getClass().getClassLoader().getResource(fileName);
Use this instead for static methods:
ClassName.class.getClassLoader().getResource(fileName);
Where fileName is the name of the file and ClassName the name of the class from which the statement is called.
In your code the path of the model.txt is 'src/models/model.txt'. When your project is packaged the src folder is not included usually. Then you must change the file location; could be better put the file outside the jar, but inside the java classpath.
It does not work because you do not have any file on the path src/models/models.txt when you run your jar else where, this path is only present in your IDE (ofcourse you can place your jar in a location from where it can reach that path, but this is not how it is supposed to be), when you package your project into a jar file it is packed in the package models and you can if you want to have it as default file read it via classpath.

Reading a TXT file in Java [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
I keep getting a java.lang.NullPointerException when trying to open a txt file in eclipse. Basically, this is a main menu, and when you click the "Rules" button, the rules text file should open. Currently, the txt file is located in a package called "Resources" (which is where all of the other img files I've used in making the game are). Here's the code:
private List<String> readFile(String filename)
{
List<String> records = new ArrayList<String>();
try
{
BufferedReader buff = new BufferedReader(new InputStreamReader(
Configuration.class.getResourceAsStream(filename)));
String line;
while ((line = buff.readLine()) != null)
{
records.add(line);
}
buff.close();
return records;
}
catch (Exception e)
{
System.err.format("Exception occurred trying to read '%s'.", filename);
e.printStackTrace();
return null;
}
}
//action performed
public void actionPerformed(ActionEvent ae) {
JButton b = (JButton)ae.getSource();
if( b.equals(newGameButton) )
{
flag = true;
controller.startGame();
buttonPressed = "newGameBtn";
}
if(b.equals(quitButton))
{
System.exit(0);
}
if(b.equals(ruleButton)){
readFile("../resource/riskRules.txt");
}
}
Appreciate the help!
If "Resources" it's marked as resource in Eclipse. The txt file should be copied to your class path when you build.
As per what I can guess from your code you should be doing something like
Configuration.class.getResourceAsStream("riskRules.txt")
Since your file will be at the root level of your class path.
If for example the file is withing a dir called "text" in your resources you would use something like
Configuration.class.getResourceAsStream("text/riskRules.txt")
There needs to be some level of rudimentary error checking on the result returned from getResourceAsStream before you attempt to use it. Is there a reason you're using getResourceAsStream instead of getResource? If the file exists on disk (I see from your OP that it's because it's in a package, and may not physically exist on the disk), then you can just use that to return the path to it, and create a file object from it.
String path = "/path/to/resource"; // note the leading '/' means "search from root of classpath"
URL fileUrl = getClass().getResource(path);
if (fileUrl != null ) {
File f = new File(fileUrl.toURI());
BufferedReader = new BufferedReader(new FileReader(f));
// do stuff here...
}
else {
// file not found...
}
If you need to pull the file out of the JAR archive, then you can do this:
String path = "/path/to/resource"; // note the leading '/' means "search from root of classpath"
InputStream is = getClass().getResourceAsStream(path);
if (is != null ) {
BufferedReader = new BufferedReader(new InputStreamReader(is));
// do stuff here...
}
else {
// file not found...
}
In the event your resource is not found, you will avoid the NPE and you can properly account for the fact that it's missing.
Note that if you do have your resources in a package (jar), then you cannot use a path to locate it that uses "..", since there is no "relative path" in a jar archive, it's not actually a file on the filesystem.
Your "resources" are located by the relative path you specify in the getResource... method. A leading "/" means to look at the root of your classpath for locating the resource. No leading "/" means to look relative to the location of the class file that you're using to locate the resource.
If your file is in a location called "com.program.resources", and you're trying to locate it from a class called "com.program.someotherpackage.MyClass", then you'd use:
getClass().getResourceAsStream("/com/program/resources/<file.txt>");
to find it.
Here's my example illustrated:
<classpath root>
com
program
resources
file.txt
img.png
someotherpackage
MyClass.class
Generally, it's common practice to leave resources outside your package structure, to avoid confusion when locating them later. Most IDE's have a way to mark your directories as resources, so when the program is compiled, they will be copied to the proper location in the classpath root, and can be found by any class asking for them.

Getting file path for local Android project files

I want to programmatically access a specific file which will be included in my project folder. Is there a way to do this? If so, where in my project folder do I put the file, and what is some simple code to get its file path?
private void saveFileToDrive() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
java.io.File spreadsheet = new java.io.File("Untitled spreadsheet.xlsx");
String filePath = spreadsheet.getAbsolutePath();
System.out.println("file path is"+filePath);
URL fileURL = getClass().getClassLoader().getResource("Untitled spreadsheet.xlsx");
String filePath2 = fileURL.getPath();
System.out.println("file path2 is"+filePath2);
java.io.File fileContent = new java.io.File(filePath);
FileContent mediaContent = new FileContent("application/vnd.ms-excel", fileContent);
File body = new File();
body.setTitle(fileContent.getName());
body.setMimeType("application/vnd.ms-excel");
File file = service.files().insert(body, mediaContent).setConvert(true).execute();
if (file != null) {
showToast("File uploaded: " + file.getTitle());
}
else
;
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
}
Put the file in root folder of your project. Then get the File URL, Path and other details as:
File file = new File("test.txt");
String filePath = file.getAbsolutePath();
EDIT: Alternate way (if the file is in your classpath e.g. put the file in "src" folder, and make sure its moved in "bin" or "classes" folder after compilation):
URL fileURL = getClass().getClassLoader().getResource(fileName);
String fileName = fileURL.getFile();
String filePath = fileURL.getPath();
This depends a lot on what type of file you want to access. You can put the file in either assets or an appropriate subdirectory of res (see Difference between /res and /assets directories).
So you want to access a file internal to your app; and you want to do so directly, rather, that is, from an Android Context (and then with a [android.|<package_name>.]R.<resource_type>.<resource_name>).
You have two choices as to location: the res/raw folder or assets/ folder (outside of the res parent).
To choose between the two note from https://developer.android.com/guide/topics/resources/providing-resources.html
Arbitrary files to save in their raw form. To open these resources with a raw InputStream, call Resources.openRawResource() with the resource ID, which is R.raw.filename.
However, if you need access to original file names and file hierarchy, you might consider saving some resources in the assets/ directory (instead of res/raw/). Files in assets/ aren't given a resource ID, so you can read them only using AssetManager.
To access a file in res/raw/ directly rather, that is, from an Android Context (and then with a [android.|<package_name>.]R.<resource_type>.<resource_name>) you can do something like this:
File file = new File("app/src/main/res/raw/country_data_from_world_bank.xml");
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));

Categories