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.
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'm using a custom method to get pictures from the resources/ folder. The hardcoded path works well when programming during production (src/main/resources/). However when delivering, I would need to make this path relative to the .jar root. So I made this.
public static Image getImageFromFile(String file)
{
Image image = null;
try
{
String path = FileUtils.class.getClassLoader().getResource(file).toExternalForm();
System.out.println(path);
File pathToFile = new File(path);
image = ImageIO.read(pathToFile);
}
catch (IOException ex) {ex.printStackTrace();}
return image;
}
file:/C:/Users/Hugo/Desktop/Hugo/Java%20Workspace/ClashBot/bin/main/icons/level-label.png
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at com.lycoon.clashbot.utils.FileUtils.getImageFromFile(FileUtils.java:55)
The printed path is valid and points to the corresponding picture. However, the program raises an IOException.
Why can't it find the file?
You're jumping through way too many hoops. It's quite simple:
FileUtils.class.getResource("path.png");
// -OR-
try (var in = FileUtils.class.getResourceAsStream("path.png")) {
// in is an inputstream.
}
is all you need. Note that this means the path.png file is searched for in the exact same place (and even same 'subdir') as where FileUtils lives. So if you have, say, a file on C:\Projects\Hugo\MyApp\myapp.jar, and if you were to unzip that, inside you'd find com/foo/pkg/FileUtils.class, then the string path.png would look in that jar, and for com/foo/pkg/path.png. In other words, AnyClass.class.getResource("AnyClass.class") will let a class find its own class file. If you want to go from the 'root' of the jar, add a slash, i.e. FileUtils.class.getResource("/path.png") looks in the same jar, and for /path.png inside that jar.
getResource returns a URL. getResourceAsStream returns a stream (which you need to close; use try-with-resources as I did). Just about every resource-using API out there will take one of these two as input. For example, ImageIO does so; it even takes a URL so you can use either one:
var image = ImageIO.read(FileUtils.class.getResource("imgName + ".png"));
Yes. It's a one-liner. This will load images straight from within a jar file!
You could try to use a slightly different call like this:
java.net.URL fileUrl = Thread.currentThread().getContextClassLoader().getResource(file);
String filePath = URLDecoder.decode(fileUrl.getPath(), "UTF-8");
image = ImageIO.read(filePath);
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 :)
This is not actually a question, but I need explanation. I was trying to create directory under C:// drive. So;
try {
File f_paz = new File("c://Ekap_Pazarlik_xml" + file_currentDate + "//");
File parent_z = f_paz.getParentFile();
if (null != parent_z) {
parent_z.mkdirs();
}
if (!f_paz.exists()) {
f_paz.createNewFile();
}
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
I tried that and it gave me "Access Denied" error, so I tried all the solutions in the web. Nothing happened.
Strangely, I decided to put "space" after there;
File f_paz = new File("c://Ekap_Pazarlik_xml" + file_currentDate + "// ");
here
just after "// ", and it worked. I was able to crate directory like that. I have no idea why it worked like that. Please provide me some explanation. Thanks !
f_paz.createNewFile(); will try to create a new file, not a directory. Many Windows systems won't allow you to create files in directly in C: so that's why you get the exception.
Since you want to create a directory and not a file use f_paz.mkdir(); instead. You don't need the "//" at the end, btw.
What happens if you add the space, i.e. use path "C:/Ekap_xxx/ "? The system will see a path with a blank filename " " and a parent directory name "Ekap_xxx". Now parent_z will refer to "C:/Ekap_xxx" and thus parent_z.mkdirs(); will create directory "Ekap_xxx". Now f_paz.exists() will return true since the filesystem seems to decide a file with an invalid name still exists (I'd have to look for some information on why that is so, it's hidden in the native code).
I am using gephi to implement a function as below, but I don't know where to put the "Personal-May8-Anoymous.gml" file so that eclipse can "see" it.
Container container;
try {
File file = new File(getClass().getResource("Personal-May8-Anoymous.gml").toURI());
container = importController.importFile(file);
container.getLoader().setEdgeDefault(EdgeDefault.DIRECTED); //Force DIRECTED
} catch (Exception ex) {
ex.printStackTrace();
return;
}
By the way it looks, the file should be places in the root of your source folders (another way to view it would be the default package). If you're using maven, put the file in the root of the resources folder.
Here's an example of the project structure:
your_project
- src
+ Personal-May8-Anoymous.gml
- some.package.here
+ YourClass
Remove this line:
File file = new File(getClass().getResource("Personal-May8-Anoymous.gml").toURI());
And modify this:
container = importController.importFile(file);
To:
container = importController.importFile(getClass().getResource("Personal-May8-Anoymous.gml").toURI());
You can see the javadoc (http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getResource%28java.lang.String%29) to understand the possible places where you can put your file, which is pretty complicated.
But, we can make it simpler, by putting your file in the location that you are familiar with, say C://Users/Personal-May8-Anoymous.gml. To do this, you need to modify:
File file = new File(getClass().getResource("Personal-May8-Anoymous.gml").toURI());
to
File file = new File("C://Users/Personal-May8-Anoymous.gml");
as simple as that.