方法一
使用jaudiotagger。此方法简单,但取较大MP3的文件头信息有错误,具体为比特率减半、时长翻倍,不建议使用。
<!-- https://mvnrepository.com/artifact/org/jaudiotagger -->
<dependency>
<groupId>org</groupId>
<artifactId>jaudiotagger</artifactId>
<version>2.0.3</version>
</dependency>
public double getMp3Size(String filename) throws Exception{
double size = 0.0f;
File file = new File(filename);
MP3File f=(MP3File)AudioFileIO.read(file);
MP3AudioHeader audioHeader=(MP3AudioHeader)f.getAudioHeader();
size = audioHeader.getTrackLength();
return size;
}
public static void main(String[] args) {
Mp3Util mu = new Mp3Util();
String filename = "D:\\MP3\\11.mp3";
double size = 0.0f;
try {
size = mu.getMp3Size(filename);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(size);
}
方法二
使用基于ffmpeg的封装库sauronsoftware。此方法依赖ffmpeg可执行文件,在windows平台和Linux平台要分别安装对应平台的ffmpeg,可移植性差,对视频的处理比较稳定,对音频处理功能不强。不建议使用。
这个包不在maven服务源,需要先下载,安装到本地源。
下载地址
http://www.sauronsoftware.it/projects/jave/jave-1.0.2.zip 下载完成后,命令行安装:
mvn install:install-file -Dfile=E:\jave-1.0.2.jar -DgroupId=it.sauronsoftware -DartifactId=jave -Dversion=1.0.2 -Dpackaging=jar

安装完成后在项目中使用
<dependency>
<groupId>it.sauronsoftware</groupId>
<artifactId>jave</artifactId>
<version>1.0.2</version>
</dependency>
可能因操作系统不同会报 ffmpeg不可执行的错误。找个可以运行的,替换下C:\Windows\Temp\jave-1\ffmpeg.exe。

ffmpeg下载地址
https://ffmpeg.org/download.html
public double getDuration(String filename) {
double size = 0.0f;
File source = new File(filename);
Encoder encoder = new Encoder();
try {
MultimediaInfo m = encoder.getInfo(source);
long ls = m.getDuration();
size = ls/1000;
System.out.println("时长为:" + size + "秒!");
} catch (Exception e) {
e.printStackTrace();
}
return size;
}
方法三
使用ffmpeg java扩展库。准确、可跨平台、不依赖ffmpeg可执行文件。(推荐使用)
参考:test-ffmpeg: java对ffmpeg的使用。无需引入ffmpeg.exe文件https://gitee.com/hsjjsh123/test-ffmpeg
<!-- https://mvnrepository.com/artifact/ws.schild/jave-all-deps -->
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-all-deps</artifactId>
<version>3.2.0</version>
</dependency>
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FfmpegCmdDurationTest {
private final static String DURATION_START = "Duration:";
private final static String KEY_FOR_HOUR = "hour";
private final static String KEY_FOR_MINUTE = "minute";
private final static String KEY_FOR_SECONED = "seconed";
private final static String KEY_FOR_MILLSECONED = "millseconed";
//小时 * 60 = 分
//分 * 60 = 秒
private final static BigDecimal GAP_60 = new BigDecimal("60");
//秒* 1000 = 毫秒
private final static BigDecimal GAP_1000 = new BigDecimal("1000");
/**
* TYPE_0:小时
* TYPE_1:分钟
* TYPE_2:秒钟
* TYPE_3:毫秒
*/
public final static int TYPE_0 = 0;
public final static int TYPE_1 = 1;
public final static int TYPE_2 = 2;
public final static int TYPE_3 = 3;
//ffmpeg执行命令
private final static String cmd_4_info = "-i D:\\MP3\\22.mp3";
public static void main(String[] args) {
try {
System.out.println(String.format("获取时长:%s 小时", duration(cmd_4_info,TYPE_0).doubleValue()));
System.out.println(String.format("获取时长:%s 分钟", duration(cmd_4_info,TYPE_1).doubleValue()));
System.out.println(String.format("获取时长:%s 秒钟", duration(cmd_4_info,TYPE_2).doubleValue()));
System.out.println(String.format("获取时长:%s 毫秒", duration(cmd_4_info,TYPE_3).doubleValue()));
System.out.println("");
System.out.println(String.format("获取时长(格式化):%s", durationFormat(cmd_4_info)));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @Description: (获取格式化的时间duration:such as:00:01:03.32)
* @param: @param cmd_4_info
* @param: @return
* @param: @throws Exception
* @return: BigDecimal
* @throws
*/
public static String durationFormat(final String cmd_4_info) throws Exception {
String duration = null;
Map<String,String> map = null;
try {
CompletableFuture<String> completableFutureTask = CompletableFuture.supplyAsync(() ->{
String durationStr = null;
//执行ffmpeg命令
StringBuffer sText = getErrorStreamText(cmd_4_info);
if(null != sText && sText.indexOf(DURATION_START) > -1) {
String stextOriginal = sText.toString();
//正则解析时间
Matcher matcher = patternDuration().matcher(stextOriginal);
//正则提取字符串
while(matcher.find()){
//such as:00:01:03.32
durationStr = matcher.group(1);
break;
}
}
return durationStr;
}, ThreadPoolExecutorUtils.pool);
duration = completableFutureTask.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return duration;
}
/**
*
* @Description: (获取时长)
* @param: @param cmd_4_info ffmpeg命令,如:-i I:\\荣耀视频测试.mp4
* @param: @param type 类型:
* TYPE_0:小时
* TYPE_1:分钟
* TYPE_2:秒钟
* TYPE_3:毫秒
* @param: @return
* @return: BigDecimal
* @throws Exception
* @throws
*/
public static BigDecimal duration(final String cmd_4_info, int type) throws Exception {
BigDecimal duration = new BigDecimal("00");
Map<String,String> map = null;
try {
CompletableFuture<Map<String,String>> completableFutureTask = CompletableFuture.supplyAsync(() ->{
Map<String,String> mapTmp = null;
//执行ffmpeg命令
StringBuffer sText = getErrorStreamText(cmd_4_info);
if(null != sText && sText.indexOf(DURATION_START) > -1) {
String stextOriginal = sText.toString();
//正则解析时间
Matcher matcher = patternDuration().matcher(stextOriginal);
//正则提取字符串
while(matcher.find()){
//such as:00:01:03.32
String durationStr = matcher.group(1);
mapTmp = getHourMinuteSeconedMillseconed(durationStr);
break;
}
}
return mapTmp;
}, ThreadPoolExecutorUtils.pool);
map = completableFutureTask.get();
if(null != map && map.size() > 0) {
switch (type) {
case TYPE_0:
//小时
duration = duration.add(new BigDecimal(map.get(KEY_FOR_HOUR)));
break;
case TYPE_1:
//分钟
duration = duration.add(new BigDecimal(map.get(KEY_FOR_HOUR)).multiply(GAP_60))
.add(new BigDecimal(map.get(KEY_FOR_MINUTE)));
break;
case TYPE_2:
//秒
duration = duration.add(new BigDecimal(map.get(KEY_FOR_HOUR)).multiply(GAP_60).multiply(GAP_60))
.add(new BigDecimal(map.get(KEY_FOR_MINUTE)).multiply(GAP_60))
.add(new BigDecimal(map.get(KEY_FOR_SECONED)));
break;
case TYPE_3:
//毫秒
duration = duration.add(new BigDecimal(map.get(KEY_FOR_HOUR)).multiply(GAP_60).multiply(GAP_60).multiply(GAP_1000))
.add(new BigDecimal(map.get(KEY_FOR_MINUTE)).multiply(GAP_60).multiply(GAP_1000))
.add(new BigDecimal(map.get(KEY_FOR_SECONED)).multiply(GAP_1000))
.add(new BigDecimal(map.get(KEY_FOR_MILLSECONED)));
break;
default:
throw new Exception("未知的类型!");
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return duration;
}
//模式
public static Pattern patternDuration() {
//"(?i)duration:\\s*([0-9\\:\\.]+)"-->匹配到时分秒即可,毫秒不需要
return Pattern.compile("(?i)duration:\\s*([0-9\\:\\.]+)");
}
/**
*
* @Description: (获取错误流)
* @param: @param cmd_4_info
* @param: @return
* @return: StringBuffer
* @throws
*/
private static StringBuffer getErrorStreamText(String cmdStr) {
//返回的text
StringBuffer sText = new StringBuffer();
FfmpegCmd ffmpegCmd = new FfmpegCmd();
try {
;
//错误流
InputStream errorStream = null;
//destroyOnRuntimeShutdown表示是否立即关闭Runtime
//如果ffmpeg命令需要长时间执行,destroyOnRuntimeShutdown = false
//openIOStreams表示是不是需要打开输入输出流:
// inputStream = processWrapper.getInputStream();
// outputStream = processWrapper.getOutputStream();
// errorStream = processWrapper.getErrorStream();
ffmpegCmd.execute(false, true, cmdStr);
errorStream = ffmpegCmd.getErrorStream();
//打印过程
int len = 0;
while ((len=errorStream.read())!=-1){
char t = (char)len;
// System.out.print(t);
sText.append(t);
}
//code=0表示正常
ffmpegCmd.getProcessExitCode();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
ffmpegCmd.close();
}
//返回
return sText;
}
/**
*
* @Description: (获取duration的时分秒毫秒)
* @param: durationStr such as:00:01:03.32
* @return: Map
* @throws
*/
private static Map<String,String> getHourMinuteSeconedMillseconed(String durationStr){
HashMap<String,String> map = new HashMap<>(4);
if(null != durationStr && durationStr.length() > 0) {
String[] durationStrArr = durationStr.split("\\:");
String hour = durationStrArr[0];
String minute = durationStrArr[1];
//特殊
String seconed = "00";
String millseconed = "00";
String seconedTmp = durationStrArr[2];
if(seconedTmp.contains("\\.")) {
String[] seconedTmpArr = seconedTmp.split("\\.");
seconed = seconedTmpArr[0];
millseconed = seconedTmpArr[1];
}
else {
seconed = seconedTmp;
}
map.put(KEY_FOR_HOUR, hour);
map.put(KEY_FOR_MINUTE, minute);
map.put(KEY_FOR_SECONED, seconed);
map.put(KEY_FOR_MILLSECONED, millseconed);
}
return map;
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorUtils {
//多线程
public static int core = Runtime.getRuntime().availableProcessors();
public static ExecutorService pool = new ThreadPoolExecutor(core,//核心
core * 2,//最大
0L,//空闲立即退出
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024),//无边界阻塞队列
new ThreadPoolExecutor.AbortPolicy());
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ws.schild.jave.process.ProcessKiller;
import ws.schild.jave.process.ProcessWrapper;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;
public class FfmpegCmd {
private static final Logger LOG = LoggerFactory.getLogger(ProcessWrapper.class);
/** The process representing the ffmpeg execution. */
private Process ffmpeg = null;
/**
* A process killer to kill the ffmpeg process with a shutdown hook, useful if the jvm execution
* is shutted down during an ongoing encoding process.
*/
private ProcessKiller ffmpegKiller = null;
/** A stream reading from the ffmpeg process standard output channel. */
private InputStream inputStream = null;
/** A stream writing in the ffmpeg process standard input channel. */
private OutputStream outputStream = null;
/** A stream reading from the ffmpeg process standard error channel. */
private InputStream errorStream = null;
/**
* Executes the ffmpeg process with the previous given arguments.
*
* @param destroyOnRuntimeShutdown destroy process if the runtime VM is shutdown
* @param openIOStreams Open IO streams for input/output and errorout, should be false when
* destroyOnRuntimeShutdown is false too
* @param ffmpegCmd windows such as (mp4 transform to mov):
* " -i C:\\Users\\hsj\\AppData\\Local\\Temp\\jave\\honer.mp4 -c copy C:\\Users\\hsj\\AppData\\Local\\Temp\\jave\\honer_test.mov "
* @throws IOException If the process call fails.
*/
public void execute(boolean destroyOnRuntimeShutdown, boolean openIOStreams, String ffmpegCmd) throws IOException {
DefaultFFMPEGLocator defaultFFMPEGLocator = new DefaultFFMPEGLocator();
StringBuffer cmd = new StringBuffer(defaultFFMPEGLocator.getExecutablePath());
//insert blank for delimiter
cmd.append(" ");
cmd.append(ffmpegCmd);
String cmdStr = String.format("ffmpegCmd final is :%s", cmd.toString());
System.out.println(cmdStr);
LOG.info(cmdStr);
Runtime runtime = Runtime.getRuntime();
try {
ffmpeg = runtime.exec(cmd.toString());
if (destroyOnRuntimeShutdown) {
ffmpegKiller = new ProcessKiller(ffmpeg);
runtime.addShutdownHook(ffmpegKiller);
}
if (openIOStreams) {
inputStream = ffmpeg.getInputStream();
outputStream = ffmpeg.getOutputStream();
errorStream = ffmpeg.getErrorStream();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Returns a stream reading from the ffmpeg process standard output channel.
*
* @return A stream reading from the ffmpeg process standard output channel.
*/
public InputStream getInputStream() {
return inputStream;
}
/**
* Returns a stream writing in the ffmpeg process standard input channel.
*
* @return A stream writing in the ffmpeg process standard input channel.
*/
public OutputStream getOutputStream() {
return outputStream;
}
/**
* Returns a stream reading from the ffmpeg process standard error channel.
*
* @return A stream reading from the ffmpeg process standard error channel.
*/
public InputStream getErrorStream() {
return errorStream;
}
/** If there's a ffmpeg execution in progress, it kills it. */
public void destroy() {
if (inputStream != null) {
try {
inputStream.close();
} catch (Throwable t) {
LOG.warn("Error closing input stream", t);
}
inputStream = null;
}
if (outputStream != null) {
try {
outputStream.close();
} catch (Throwable t) {
LOG.warn("Error closing output stream", t);
}
outputStream = null;
}
if (errorStream != null) {
try {
errorStream.close();
} catch (Throwable t) {
LOG.warn("Error closing error stream", t);
}
errorStream = null;
}
if (ffmpeg != null) {
ffmpeg.destroy();
ffmpeg = null;
}
if (ffmpegKiller != null) {
Runtime runtime = Runtime.getRuntime();
runtime.removeShutdownHook(ffmpegKiller);
ffmpegKiller = null;
}
}
/**
* Return the exit code of the ffmpeg process If the process is not yet terminated, it waits for
* the termination of the process
*
* @return process exit code
*/
public int getProcessExitCode() {
// Make sure it's terminated
try {
ffmpeg.waitFor();
} catch (InterruptedException ex) {
LOG.warn("Interrupted during waiting on process, forced shutdown?", ex);
}
return ffmpeg.exitValue();
}
/**close**/
public void close() {
destroy();
}
}
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
如何在Ruby中获取BasicObject实例的类名?例如,假设我有这个:classMyObjectSystem我怎样才能使这段代码成功?编辑:我发现Object的实例方法class被定义为returnrb_class_real(CLASS_OF(obj));。有什么方法可以从Ruby中使用它? 最佳答案 我花了一些时间研究irb并想出了这个:classBasicObjectdefclassklass=class这将为任何从BasicObject继承的对象提供一个#class您可以调用的方法。编辑评论中要求的进一步解释:假设你有对象