[英]Program runs completely in Eclipse but does not run when exported as a Runnable JAR file
I have a main class that looks like this: 我有一个主班,看起来像这样:
package complete;
import java.io.File;
import java.io.*;
import javax.sound.sampled.*;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.BooleanControl;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Presentation");
frame.setSize(806, 506);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(new GameFrame());
frame.setVisible(true);
sound = new File("Assets/BackgroundSound.wav"); // Write you own file location here and be aware that it need to be an .wav file
new Thread(play).start();
}
static File sound;
static boolean muted = false; // This should explain itself
static float volume = 100.0f; // This is the volume that goes from 0 to 100
static float pan = 0.0f; // The balance between the speakers 0 is both sides and it goes from -1 to 1
static double seconds = 0.0d; // The amount of seconds to wait before the sound starts playing
static boolean looped_forever = true; // It will keep looping forever if this is true
static int loop_times = 0; // Set the amount of extra times you want the sound to loop (you don't need to have looped_forever set to true)
static int loops_done = 0; // When the program is running this is counting the times the sound has looped so it knows when to stop
final static Runnable play = new Runnable() // This Thread/Runnabe is for playing the sound
{
public void run()
{
try
{
// Check if the audio file is a .wav file
if (sound.getName().toLowerCase().contains(".wav"))
{
AudioInputStream stream = AudioSystem.getAudioInputStream(sound);
AudioFormat format = stream.getFormat();
if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED)
{
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
format.getSampleRate(),
format.getSampleSizeInBits() * 2,
format.getChannels(),
format.getFrameSize() * 2,
format.getFrameRate(),
true);
stream = AudioSystem.getAudioInputStream(format, stream);
}
SourceDataLine.Info info = new DataLine.Info(
SourceDataLine.class,
stream.getFormat(),
(int) (stream.getFrameLength() * format.getFrameSize()));
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
line.open(stream.getFormat());
line.start();
// Set Volume
FloatControl volume_control = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN);
volume_control.setValue((float) (Math.log(volume / 100.0f) / Math.log(10.0f) * 20.0f));
// Mute
BooleanControl mute_control = (BooleanControl) line.getControl(BooleanControl.Type.MUTE);
mute_control.setValue(muted);
FloatControl pan_control = (FloatControl) line.getControl(FloatControl.Type.PAN);
pan_control.setValue(pan);
long last_update = System.currentTimeMillis();
double since_last_update = (System.currentTimeMillis() - last_update) / 1000.0d;
// Wait the amount of seconds set before continuing
while (since_last_update < seconds)
{
since_last_update = (System.currentTimeMillis() - last_update) / 1000.0d;
}
//System.out.println("Playing!");
int num_read = 0;
byte[] buf = new byte[line.getBufferSize()];
while ((num_read = stream.read(buf, 0, buf.length)) >= 0)
{
int offset = 0;
while (offset < num_read)
{
offset += line.write(buf, offset, num_read - offset);
}
}
line.drain();
line.stop();
if (looped_forever)
{
new Thread(play).start();
}
else if (loops_done < loop_times)
{
loops_done++;
new Thread(play).start();
}
}
}
catch (Exception ex) { ex.printStackTrace(); }
}
};
}
When I run the runnable JAR, the frame opens with the correct size and title but with a blank screen. 当我运行可运行的JAR时,框架以正确的大小和标题打开,但屏幕空白。
When I run from the command line I get this error: 当我从命令行运行时,出现此错误:
java.io.FileNotFoundException: Assets\BackgroundSound.wav <The system cannot find the path specified>
at java.io.FileInputStream.open<Native Method>
at java.io.FileInputStream.<init><Unknown Source>
at com.sun.media.sound.WaveFloatFileReader.getAudioInputStream<Unknown Source>
at javax.sound.sampled.AudioSystem.getAudioInputStream<Unknown Source>
at complete.Main$1.run<Main.Java:50>
at java.lang.Thread.run<Unknown Source>
I have extracted the files from the JAR and all the classes, images and the WAV file are there. 我已经从JAR中提取了文件,并且所有的类,图像和WAV文件都在那里。
When I remove the sound section from the Main class and run in Eclipse, the program runs completely and without sound as expected. 当我从Main类中删除声音部分并在Eclipse中运行时,该程序将完全运行且没有预期的声音。
When I export this version as a Runnable JAR, the same thing happens as before when I attempted to run it, except this time there are no command line errors. 当我将此版本导出为可运行的JAR时,与尝试运行它时发生的事情相同,只是这次没有命令行错误。
要从jar中加载文件,您需要使用getResources或getResourceAsStream。
采用:
sound = new File(Main.class.getResource("Assets/BackgroundSound.wav").getPath());
The data for sound
is not contained in a file on your disk directly; sound
数据不直接包含在磁盘上的文件中; it is inside the jar file for your project. 它在您的项目的jar文件中。 So, using
File
to access it is incorrect. 因此,使用
File
访问它是不正确的。 Instead, use the overloaded AudioStream
method: 而是使用重载的
AudioStream
方法:
public static AudioInputStream getAudioInputStream(InputStream stream)
throws UnsupportedAudioFileException,
IOException
Obtains an audio input stream from the provided input stream.
从提供的输入流中获取音频输入流。 The stream must point to valid audio file data.
流必须指向有效的音频文件数据。 The implementation of this method may require multiple parsers to examine the stream to determine whether they support it.
此方法的实现可能需要多个解析器来检查流,以确定它们是否支持该流。 These parsers must be able to mark the stream, read enough data to determine whether they support the stream, and, if not, reset the stream's read pointer to its original position.
这些解析器必须能够标记流,读取足够的数据以确定它们是否支持该流,如果不能,则将流的读取指针重置为其原始位置。 If the input stream does not support these operation, this method may fail with an IOException.
如果输入流不支持这些操作,则此方法可能会失败,并出现IOException。
You get the InputStream
by using Class.getResourceAsStream(String name)
. 您可以使用
Class.getResourceAsStream(String name)
获得InputStream
。 That will look on the class path, and so can be set to work in both Eclipse and from a jar file. 这将在类路径上查找,因此可以设置为在Eclipse和jar文件中均可使用。 Easiest is to move the sound file to be alongside your class file, so you can just use:
最简单的方法是将声音文件移到类文件的旁边,因此您可以使用:
InputStream soundResource = Main.class.getResourceAsStream("BackgroundSound.wav");
AudioInputStream ais = AudioSystem.getAudioInputStream(soundResource);
Sorry--I needed to edit the last part--I forgot that this was all in main
. 抱歉-我需要编辑最后一部分-我忘了这一切都是
main
。 Try not to do that for any but the most trivial programs. 尝试对最琐碎的程序不要这样做。 Instead, instantiate the class and have the instance do things.
而是实例化该类并让实例执行操作。 And rename the class from
Main
to something like SoundDemo
. 并将
Main
的类重命名为SoundDemo
。 Otherwise in three months you'll say to yourself, "Where did I do that exercise on learning how to have Java play sounds? What file was it in? It was in Main
? Really?" 否则,在三个月内您将对自己说:“我在哪里进行了该练习以学习如何播放Java声音?它在哪个文件中?它在
Main
吗?真的吗?”
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.