So my task is to create a small program that displays a list of media files and run these media files with default OS media player separately.
My current solution was to create a package that holds all media files, something like:
-com.media
|_a.mp4
|_b.mp4
The following code copies to a temp dir the selected mp4, then runs the default os media player:
public File copyTempMedia(File tempAppFolder, String videoName) {
URL f = getClass().getResource(String.format("%s/%s", Constants.MEDIA_LOCATION, videoName));
File from = new File(f.getPath());
File to = new File(tempAppFolder.getAbsolutePath());
try {
FileUtils.copyFileToDirectory(from, to);
} catch (IOException ex) {
Logger.getLogger(MediGUIModel.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Temp video copied: " + to.getAbsolutePath() + "/" + to.getName());
return to;
}
public void triggerMediaPlayer(String fileLocation) {
System.out.println("Triggering media player: " + fileLocation);
try {
if (OPERATIN_SYSTEM.contains("Linux")) {
Runtime.getRuntime().exec("sh -c " + fileLocation);
} else if (OPERATIN_SYSTEM.contains("Windows")) {
Runtime.getRuntime().exec("cmd /c " + fileLocation);
}
} catch (IOException ex) {
Logger.getLogger(MediGUIModel.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
When I run the program through Netbeans it works as espected, but when I do a clean/build the run the .jar created from the build, the media file doesn't seem to be read, so my questions are:
Why does it work through Netbeans and not through build .jar ?
Is this the best solution to this problem ?
Should I package the media differently ?
Thanks in advance.
Edit
So after running through console instead of double clicking jar, is get a null pointer exception in the line where I read the file:
URL f = getClass().getResource(String.format("%s/%s", Constants.MEDIA_LOCATION, videoName));
Why does it work in Netebeans but not on build/jar ?
Is there another place in the jar I could place the media files, so that they are read with no problem through getResource or getResourceAsStream ?
When you run the project in NetBeans, it isn't running the executable jar like java -jar yourproject.jar. Instead it sets the classpath to build/classes sort of like java -cp build/classes com.media.YourMainClass. This means your video files are actual files located in yourproject/build/classes/com/media, and they can be accessed as normal files in the filesystem and copied like a normal file. When you run from the jar, the files are packed in the jar file and can't be copied using simple file copy commands.
Instead of getting the URL by calling getClass().getResource(), try getting an InputStream by calling getClass().getResourceAsStream(). You can then write a simple loop to copy the bytes from the input stream to your temporary file.
This snippet may be helpful:
BufferedInputStream result = (BufferedInputStream) getClass().getResourceAsStream("/com/media/a.mp4");
byte[] bytes = new byte[4098];
try {
result.read(bytes);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new String(bytes));
You'll need to read the bytes in a loop or something but that should work without needing a separate jar.
I think it's not a good idea to put your media files in the jar because you need to rebuild the project if you want to change one and the jar size will grow.
Use:
File from = new File(String.format("%s/%s", Constants.MEDIA_LOCATION,videoName));
To load your files from the same folder as the jar.
If you want to keep the medias in the jar, create a Maven project and put the mp4 in src/main/resources.
Use maven to create a fat jar and the src/main/resources will be included in the jar.
See 'maven-shade-plugin' to configure the pom.xml and https://www.mkyong.com/maven/create-a-fat-jar-file-maven-shade-plugin/
Then you can use the others maven's great properties!
See Reading a resource file from within jar
Edit
After some tries, i can't get it right with 'getResource' from the jar.
The path you get from within the jar is like:file:/C:/.../JavaApplication4/dist/JavaApplication4.jar!/test.txt
and not recognized as a valid filesystem path.
You can use 'getResourceAsStream' and copy the file from the jar to the local folder.
InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();
Ok so I found a solution:
Create a separate project with media.*.mp4.
Export as Jar library.
Import library to desktop app.
Make sure library is in classpath.
This solution works for me...
If anyone has a better solution, happy to hear, hopefully before bounty is up :)
Related
tl;dr I'm more used to writing command-line scripts that can just output based on the current working directory, so I'm unsure what directory to use for output files in a program that will be launched from a JAR.
Program Description:
My program builds an HTML file from data given to it from the rest of the program, and then is supposed to write it to a file that we'll call "Output.html" for simplicity.
Relevant Code:
public void outputHTML()
{
String output = buildHTML();
// Expanded to explain my confusion better
String fileDirectory = ""; // ???
String fileName = "Output.html";
String fullPath = fileDirectory + "\\" + fileName;
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fullPath)))
{
writer.write(output);
writer.close();
} catch (IOException e)
{
System.out.println("File not found.");
e.printStackTrace();
}
}
Problem
I don't know what to put the file directory as. Usually I run my programs from the command line and use ".\\Output.txt" as my output path, but I don't know where to put it if it's being run from a JAR.
The desired file structure is as follows:
Encompassing Folder
Program.jar
output
Output.html
Or alternatively (not sure if this makes it easier to understand or harder):
main\
main\Program.jar
main\output\
main\output\Output.html
Everything I can find on SE only relates to reading files that are both immutable and internal, but I'm trying to output a non-static file to a location outside of my jar.
Can anyone help with this? Thanks!
Misc Details
I'm using Eclipse without Gradle currently, because I don't know what Gradle is and new things are scary. If this particular problem would be easier to solve with Gradle, let me know and I'll look up more about it.
EDIT:
Added syntax highlighting to code block.
Formatted everything a bit better
Changed title to be more descriptive
You can use an absolute path: e.g. fileDirectory = "\\project\\test\\main\\output";
using normal slash should also work even on Windows ("/project/test/main/output")
Or use a relative path - this will start from the current working directory (user directory), the one where the JVM was started in - e.g. fileDirectory = "main\\output";
I have deployed a spring-boot application JAR file. Now, I want to upload the image from android and store it in the myfolder of resource directory. But unable to get the path of resource directory.
Error is:
java.io.FileNotFoundException: src/main/resources/static/myfolder/myimage.png
(No such file or directory)
This is the code for storing the file in the resource folder
private final String RESOURCE_PATH = "src/main/resources";
String filepath = "/myfolder/";
public String saveFile(byte[] bytes, String filepath, String filename) throws MalformedURLException, IOException {
File file = new File(RESOURCE_PATH + filepath + filename);
OutputStream out = new FileOutputStream(file);
try {
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
return file.getName();
}
UPDATED:
This is what I have tried
private final String RESOURCE_PATH = "config/";
controller class:
String filepath = "myfolder/";
String filename = "newfile.png"
public String saveFile(byte[] bytes, String filepath, String filename) throws MalformedURLException, IOException {
//reading old file
System.out.println(Files.readAllBytes(Paths.get("config","myfolder","oldfile.png"))); //gives noSuchFileException
//writing new file
File file = new File(RESOURCE_PATH + filepath + filename);
OutputStream out = new FileOutputStream(file); //FileNotFoundException
try {
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
return file.getName();
}
Project structure:
+springdemo-0.0.1-application.zip
+config
+myfolder
-oldfile.png
-application.properties
+lib
+springdemo-0.0.1.jar
+start.sh
-springdemo-0.0.1.jar //running this jar file
Usually when you deploy an application (or start it using Java), you start a JAR file. You don't have a resource folder. You can have one and access it, too, but it certainly won't be src/main/resources.
When you build your final artifact (your application), it creates a JAR (or EAR or WAR) file and your resources, which you had in your src/main/resources-folder, are copied over to the output directory and included in the final artifact. That folder simply does not exist when the application is run (assuming you are trying to run it standalone).
During the build process target/ is created and contains the classes, resources, test-resources and the likes (assuming you are building with Maven; it is a little different if you build using Gradle or Ant or by hand).
What you can do is create a folder e.g. docs next to your final artifact, give it the appropriate permissions (chmod/chown) and have your application output files into that folder. This folder is then expected to exist on the target machine running your artifact, too, so if it doesn't, it would mean the folder does not exist or the application lacks the proper permissions to read from / write to that folder.
If you need more details, don't hesitate to ask.
Update:
To access a resource, which is bundled and hence inside your artifact (e.g. final.jar), you should be able to retrieve it by using e.g. the following:
testText = new String(ControllerClass.class.getResourceAsStream("/test.txt").readAllBytes());
This is assuming your test.txt file is right under src/main/resources and was bundled to be directly in the root of your JAR-file (or target folder where your application is run from). ControllerClass is the controller, which is accessing the file. readAllBytes just does exactly this: read all the bytes from a text file. For accessing images inside your artifact, you might want to use ImageIO.
IF you however want to access an external file, which is not bundled and hence not inside your artifact, you may use File image = new File(...) where ... would be something like "docs/image.png". This would require you to create a folder called docs next to your JAR-artifact and put a file image.png inside of it.
You of course also may work with streams and there are various helpful libraries for working with input- and output streams.
The following was meant for AWT, but it works in case you really want to access the bytes of your image: ImageIO. In a controller you usually wouldn't want to do that, but rather have your users access (and thus download) it from a given available folder.
I hope this helps :).
I am making an simple application to play sounds in Java. I am able to do that when I keep the audio files in D: disk. Here is the code
in = new FileInputStream("D:\\"+selectedSounds[position]+".wav");
//Some code for playing audio
Then I placed the audio files in same package where the Jframe class is present. But when I run it prompts fileNotFound exception. Can some one tell me why this is happening.
in = new FileInputStream(selectedSounds[position]+".wav");
// I have also tried
new FileInputStream("./"+selectedSounds[position]+".wav");
Here is the file path
Your wave file, contained within the "Source Packages" won't be accessible once the program is packaged as a Jar, as the files will be embedded within the Jar itself and no longer accessible as files.
Instead, you should be using Class#getResourceAsStream, for example...
try (InputStream in = getClass().getResourceAsStream("/PlayAudio/" + selectedSounds[position]+".wav")) {
// You now have an InputStream to your resource, have fun
} catch (IOException | NullPointerException exp) {
exp.printStackTrace();
}
I would like to know how to create a runnable JAR with resources (pictures, pdfs) in a resource folder either inside or outside the source package (ie /src/resources/images/ or /resources/images/) in Eclipse. Currently, i have my resources inside the source folder of my eclipse project, but I've also tried it inside its own folder in the package. The program builds and executes fine in eclipse, but when I go to export as a runnable jar, I keep getting a file not found exception when I run it on the desktop. I'm declaring my files with a string like this
private String file = "src/resources/orderForm.pdf";
I understand that I should user getResourceAsStream(), but due to some constraints, I can't (has to do with how files are saved, I'm reading in whole pdf files, not as streams) so I'm wondering how to get my files into the correct location in the jar. If i unpack it after I've made it they always show up in the top level, outside of the folders. Here is a screen shot of my current project structure. For the sake of saying it, this project works fine in eclipse, also in the java build properties, the source folder is in the build path along with all subfolders, I also tried doing the same with the empty resources folder in an earlier test.
You will need to do the getResourceAsStream, and make sure that the pdfs get built into the jar. Since you have them in the source folder, they should.
Assuming you have the pdf under src/resources/orderForm.pdf, it will end up in the jar file as /resources/orderForm.pdf. You would open a resource stream for /resources/orderForm.pdf.
If you must have a honest to goodness file, then you would need code that reads the PDF as a resource stream, FileOutputStreams it out to a temp file, then uses the file. Or, you simply cannot package the pdfs in the jar.
public class PDFWriter {
public static final String testDir = "C:\\pdftest\\";
public static final String adobePath = "\"C:\\Program Files\\Adobe\\Reader 10.0\\Reader\\AcroRd32.exe\"";
public static void main(String[] args){
try {
new PDFWriter().run();
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() throws Exception {
InputStream in = this.getClass().getResourceAsStream("/resources/test.pdf");
new File(testDir).mkdirs();
String pdfFilePath = testDir + "test.pdf";
FileOutputStream out = new FileOutputStream (pdfFilePath);
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
out.close();
Runtime rt = Runtime.getRuntime();
String command = adobePath + " " + pdfFilePath;
rt.exec(command);
}
}
The only reason the file way works at all in eclipse is because the bin folder is a real folder, but when you build the thing, it all gets zipped up into a jar.
Maybe a bit of confusion over source folders. If you have a source folder called 'src', the package structure under it does not contain "src". src/net/whatever/Class.java will turn into net/whatever/Class.class when build.
So, you could create a second source folder called 'rsrc' (resources), and under this put your resources/order.pdf. rsrc/resources/order.pdf will become resources.order.pdf when you build the jar.
For the sake of easy exporting from Eclipse without constantly thinking about it, I recommend putting the resources folder under the src folder. Long story short, if you don't put it in your src folder, every time you create a jar, you will need to check the box next to the resources folder. So just put it in the src folder and save yourself some problems.
As for referrencing the files, I would try
private String file = "resources/finished.pdf";
This allows you to access the file under src/resources/finished.pdf.
This is the first time I've implemented sounds but I can't figure out where to actually place the sounds to play them. I am using Eclipse as my IDE and I've put my sounds in a folder called sounds.
The following code is what I've used to create one of the audioclip objects:
private final String background = "." + slash + "sounds" + slash + "background.wav";
main(....){
try {
backgroundClip = Applet.newAudioClip(new File(background).toURI().toURL());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I don't hear anything. When I remove the try/catch I get an error saying that it is unable to find the file. I placed my sound folder in both /src and /bin but neither can find it. where do I put it?
The base for your project is the level above the src folder. So using . will put you at your project folder.
Basically,
. = project_root
./src = default_package
./src/packagename = inside the package named "packagename"
./sounds/background.wav = a .wav file in the sounds folder, in the project_root
Using your current path, you need to put your .wav file in the sounds folder in the project_root.
The path will end up being project_root/sounds/background.wav.
See this thread to understand why application resources should be obtained by URL obtained from getResource(), rather than a File converted to an URL.