ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java
@@ -1,17 +1,15 @@ package com.ruoyi.media.controller; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.media.domain.MediaInfo; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.media.domain.StreamInfo; import com.ruoyi.media.service.IMediaService; import com.ruoyi.media.service.impl.MediaService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -24,39 +22,45 @@ **/ @RestController @Api(tags = "æµåªä½æ¥å£") @Anonymous public class MediaController { @RequestMapping("/media/stream") public class MediaController extends BaseController { @Resource private IMediaService mediaService; @PostMapping("/add") @ApiOperation("å¢å 转ç ") public AjaxResult addPath(@RequestBody MediaInfo mediaInfo) { String rtsp = mediaService.addPath(mediaInfo.getCameraId(), mediaInfo.getRtspPath()); @ApiOperationSupport(includeParameters = {"streamInfo.name","streamInfo.rtspSource"}) public AjaxResult addPath(@RequestBody StreamInfo streamInfo) { String rtsp = mediaService.addPath(streamInfo.getName(), streamInfo.getRtspSource()); return AjaxResult.success(rtsp); } @PostMapping("/remove") @ApiOperation("ç§»é¤è½¬ç ") @ApiOperationSupport(includeParameters={"mediaInfo.cameraId"}) public AjaxResult removePath(@RequestBody MediaInfo mediaInfo) { mediaService.removePath(mediaInfo.getCameraId()); @ApiOperationSupport(includeParameters = {"streamInfo.name"}) public AjaxResult removePath(@RequestBody StreamInfo streamInfo) { mediaService.removePath(streamInfo.getName()); return AjaxResult.success(); } @GetMapping("/getPaths") @ApiOperation("è·åå½å转ç å表") public AjaxResult getPaths() { return AjaxResult.success(mediaService.paths()); } @GetMapping("/getRtspSessions") @ApiOperation("è·årtspä¼è¯å表") public AjaxResult getRtspSessions() { return AjaxResult.success(mediaService.rtspsessions()); } @GetMapping("/getRtspConns") @ApiOperation("è·årtspè¿æ¥å表") public AjaxResult getRtspConns() { return AjaxResult.success(mediaService.rtspconns()); } @GetMapping("/getRtspSessionById") @ApiOperation("æIDæ¥è¯¢ä¼è¯") public AjaxResult getRtspSessionById(String sessionId) { @@ -68,9 +72,53 @@ public AjaxResult getPushStreams() { return AjaxResult.success(mediaService.getPushStreams()); } @GetMapping("/getPullStreams") @ApiOperation("è·åææµä¿¡æ¯") public AjaxResult getPullStreams() { return AjaxResult.success(mediaService.getPullStreams()); } @PreAuthorize("@ss.hasPermi('media:stream:list')") @GetMapping("/pushList") @ApiOperation("è·åæ¨æµå表") public TableDataInfo getPushStreamList() { startPage(); return getDataTable(mediaService.getPushStreamList()); } /** * æ°å¢æµåªä½æ¨æµ */ @PreAuthorize("@ss.hasPermi('media:stream:add')") @PostMapping @ApiOperationSupport(includeParameters = {"streamInfo.name"}) public AjaxResult add(@RequestBody StreamInfo streamInfo) throws InterruptedException { String rtsp = mediaService.addPath(streamInfo.getName(), streamInfo.getRtspSource()); return AjaxResult.success(rtsp); } /** * å 餿µåªä½æ¨æµ */ @PreAuthorize("@ss.hasPermi('media:stream:remove')") @DeleteMapping("/path/{name}") public AjaxResult remove(@PathVariable String name) { mediaService.removePath(name); return AjaxResult.success(); } /** * å 餿µåªä½ææµ */ @PreAuthorize("@ss.hasPermi('media:stream:remove')") @DeleteMapping("/{id}") public AjaxResult removePullStreamSession(@PathVariable String id) { return AjaxResult.success(mediaService.kickRtspSession(id)); } @PreAuthorize("@ss.hasPermi('media:stream:list')") @GetMapping("/pullList") @ApiOperation("è·åææµå表") public TableDataInfo getPullStreamList() { startPage(); return getDataTable(mediaService.getPullStreamList()); } } ard-work/src/main/java/com/ruoyi/media/domain/MediaInfo.java
ÎļþÒÑɾ³ý ard-work/src/main/java/com/ruoyi/media/domain/RtspSession.java
@@ -1,5 +1,6 @@ package com.ruoyi.media.domain; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.util.Date; @@ -13,8 +14,9 @@ */ @Data public class RtspSession { private String cameraId; private String name; private String id; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date created; private String remoteAddr; private String state; ard-work/src/main/java/com/ruoyi/media/domain/StreamInfo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,60 @@ package com.ruoyi.media.domain; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; import java.util.Date; /** * @Description:æµä¿¡æ¯ * @ClassName: PushStreamInfo * @Author: åèä¹ * @Date: 2023å¹´07æ15æ¥8:40:37 * @Version: 1.0 **/ @Data @JsonInclude(value = JsonInclude.Include.NON_NULL) public class StreamInfo { /** * ä¼è¯ID */ String id; /** * è·¯å¾åç§° */ String name; /** * æºrtspå°å */ String rtspSource; /** * rtspææ¾å°å */ String rtspUrl; /** * ä¼ è¾æ¹å¼ */ String protocol; /** * ä¸è¡æµé */ String upTraffic; /** * ä¸è¡æµé */ String downTraffic; /** * ææµæ°é */ Integer num; /** * å¼å§æ¶é´ */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date beginTime; /** * è¿ç¨ä¸»æº */ String remoteAddr; } ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java
@@ -1,6 +1,7 @@ package com.ruoyi.media.service; import com.ruoyi.media.domain.Items; import com.ruoyi.media.domain.RtspSession; import com.ruoyi.media.domain.StreamInfo; import java.util.List; @@ -11,7 +12,15 @@ public List<Items>paths(); public List<Items> rtspconns(); public List<Items> rtspsessions(); RtspSession getRtspSessionById(String sessionId); List<RtspSession>getPushStreams(); List<RtspSession>getPullStreams(); List<StreamInfo>getPushStreamList(); List<StreamInfo>getPullStreamList(); Boolean kickRtspSession(String sessionId); } ard-work/src/main/java/com/ruoyi/media/service/impl/MediaService.java
@@ -4,12 +4,15 @@ import com.ruoyi.media.domain.*; import com.ruoyi.media.service.IMediaService; import com.ruoyi.utils.forest.MediaClient; import com.ruoyi.utils.tools.ArdTool; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @Description: @@ -29,8 +32,8 @@ @Override public String addPath(String name, String rtspPath) { String apiUrl="http://"+mediamtxHost+":9997/v2"; String rtspUrl="rtsp://"+mediamtxHost+":8554/"; String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String rtspUrl = "rtsp://" + mediamtxHost + ":8554/"; Conf mediaInfo = new Conf(); //-vcodec libx264 //æå®è§é¢ç¼ç å¨ä¸º libx264ï¼ä½¿ç¨ H.264 ç¼ç æ ¼å¼è¿è¡è§é¢å缩 //-preset ultrafast //--presetç忰䏻è¦è°èç¼ç é度åè´¨éçå¹³è¡¡ï¼æultrafastï¼è½¬ç é度æå¿«ï¼è§é¢å¾å¾ä¹ææ¨¡ç³ï¼ãsuperfastãveryfastãfasterãfastãmediumãslowãslowerãveryslowãplaceboè¿10个é项ï¼ä»å¿«å°æ ¢ @@ -42,22 +45,24 @@ //CPU软解ç ç¼ç String cmd = "ffmpeg -rtsp_transport tcp -i \"" + rtspPath + "\" -vcodec libx264 -preset:v ultrafast -r 25 -threads 4 -b:v 4096k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH"; //GPU硬解ç ç¼ç -hwaccel cuvid -c:v h264_cuvid 使ç¨cudaè§£ç -c:v h264_nvenc 使ç¨cudaç¼ç //String cmd = "ffmpeg -hwaccel cuvid -c:v h264_cuvid -rtsp_transport udp -i \"" + rtspPath + "\" -c:v h264_nvenc -r 25 -threads 4 -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH"; mediaInfo.setRunoninit(cmd); mediaInfo.setRunoninitrestart(true); //String cmd = "ffmpeg -hwaccel cuvid -c:v h264_cuvid -rtsp_transport udp -i \"" + rtspPath + "\" -c:v h264_nvenc -r 25 -threads 4 -b:v 4096k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH"; // mediaInfo.setRunoninit(cmd); // mediaInfo.setRunoninitrestart(true); mediaInfo.setRunondemand(cmd); mediaInfo.setRunondemandrestart(true); mediaClient.addPath(apiUrl, name, mediaInfo); return rtspUrl + name; } @Override public void removePath(String name) { String apiUrl="http://"+mediamtxHost+":9997/v2"; String apiUrl = "http://" + mediamtxHost + ":9997/v2"; mediaClient.removePath(apiUrl, name); } @Override public List<Items> paths() { String apiUrl="http://"+mediamtxHost+":9997/v2"; String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.paths(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); return jsonsRoot.getItems(); @@ -65,7 +70,7 @@ @Override public List<Items> rtspconns() { String apiUrl="http://"+mediamtxHost+":9997/v2"; String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.rtspconns(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); return jsonsRoot.getItems(); @@ -73,7 +78,7 @@ @Override public List<Items> rtspsessions() { String apiUrl="http://"+mediamtxHost+":9997/v2"; String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.rtspsessions(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); return jsonsRoot.getItems(); @@ -81,24 +86,23 @@ @Override public RtspSession getRtspSessionById(String sessionId) { String apiUrl="http://"+mediamtxHost+":9997/v2"; String list = mediaClient.getRtspsessionById(apiUrl,sessionId); String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.getRtspsessionById(apiUrl, sessionId); RtspSession rtspSession = JSONObject.parseObject(list, RtspSession.class); return rtspSession; } @Override public List<RtspSession> getPushStreams() { List<RtspSession> rtspSessions=new ArrayList<>(); String apiUrl="http://"+mediamtxHost+":9997/v2"; List<RtspSession> rtspSessions = new ArrayList<>(); String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.paths(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); List<Items> items = jsonsRoot.getItems(); for(Items item:items) { for (Items item : items) { Source source = item.getSource(); RtspSession rtspSession = getRtspSessionById(source.getId()); rtspSession.setCameraId(item.getName()); rtspSession.setName(item.getName()); rtspSessions.add(rtspSession); } return rtspSessions; @@ -106,20 +110,137 @@ @Override public List<RtspSession> getPullStreams() { List<RtspSession> rtspSessions=new ArrayList<>(); String apiUrl="http://"+mediamtxHost+":9997/v2"; List<RtspSession> rtspSessions = new ArrayList<>(); String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.paths(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); List<Items> items = jsonsRoot.getItems(); for(Items item:items) { for (Items item : items) { List<Readers> readers = item.getReaders(); for(Readers reader:readers) { for (Readers reader : readers) { RtspSession rtspSession = getRtspSessionById(reader.getId()); rtspSession.setCameraId(item.getName()); rtspSession.setName(item.getName()); rtspSessions.add(rtspSession); } } return rtspSessions; } @Override public List<StreamInfo> getPushStreamList() { List<StreamInfo> PushStreamInfoList = new ArrayList<>(); String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.paths(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); List<Items> items = jsonsRoot.getItems(); for (Items item : items) { StreamInfo info = new StreamInfo(); //ID String name = item.getName(); info.setName(name); //RTSPææ¾å°å String rtspUrl = "rtsp://" + mediamtxHost + ":8554/" + name; info.setRtspUrl(rtspUrl); Source source = item.getSource(); if(source==null) { continue; } RtspSession rtspSession = getRtspSessionById(source.getId()); //ä¼è¯ID info.setId(rtspSession.getId()); //å¼å§æ¨æµæ¶é´ info.setBeginTime(rtspSession.getCreated()); //ä¸è¡æµé long bytesReceived = rtspSession.getBytesReceived(); String formatReceivedSize = ArdTool.formatFileSize(bytesReceived); info.setUpTraffic(formatReceivedSize); //ä¸è¡æµé long bytesSent = rtspSession.getBytesSent(); String formatSentSize = ArdTool.formatFileSize(bytesSent); info.setDownTraffic(formatSentSize); //RTSPæºå°å //String runoninit = item.getConf().getRunoninit(); String runoninit = item.getConf().getRunondemand(); String regex = "rtsp://[^\\s\"]+"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(runoninit); if (matcher.find()) { info.setRtspSource(matcher.group()); } //ä¼ è¾åè®® regex = "-rtsp_transport\\s+(\\w+)"; pattern = Pattern.compile(regex); matcher = pattern.matcher(runoninit); if (matcher.find()) { info.setProtocol(matcher.group(1)); } //ææµæ°é List<Readers> readers = item.getReaders(); info.setNum(readers.size()); //æ¨æµæå¡å¨ info.setRemoteAddr(rtspSession.getRemoteAddr()); PushStreamInfoList.add(info); } return PushStreamInfoList; } @Override public List<StreamInfo> getPullStreamList() { List<StreamInfo> PullStreamInfoList = new ArrayList<>(); String apiUrl = "http://" + mediamtxHost + ":9997/v2"; String list = mediaClient.paths(apiUrl); JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class); List<Items> items = jsonsRoot.getItems(); for (Items item : items) { StreamInfo info = new StreamInfo(); //ID String name = item.getName(); info.setName(name); //RTSPææ¾å°å String rtspUrl = "rtsp://" + mediamtxHost + ":8554/" + name; info.setRtspUrl(rtspUrl); List<Readers> readers = item.getReaders(); for (Readers reader : readers) { RtspSession rtspSession = getRtspSessionById(reader.getId()); //ä¼è¯ID info.setId(rtspSession.getId()); //å¼å§ææµæ¶é´ info.setBeginTime(rtspSession.getCreated()); //ä¸è¡æµé long bytesReceived = rtspSession.getBytesReceived(); String formatReceivedSize = ArdTool.formatFileSize(bytesReceived); info.setUpTraffic(formatReceivedSize); //ä¸è¡æµé long bytesSent = rtspSession.getBytesSent(); String formatSentSize = ArdTool.formatFileSize(bytesSent); info.setDownTraffic(formatSentSize); //ä¼ è¾åè®® String runoninit = item.getConf().getRunondemand(); String regex = "-rtsp_transport\\s+(\\w+)"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(runoninit); if (matcher.find()) { info.setProtocol(matcher.group(1)); } //ææµæå¡å¨ info.setRemoteAddr(rtspSession.getRemoteAddr()); PullStreamInfoList.add(info); } } return PullStreamInfoList; } @Override public Boolean kickRtspSession(String sessionId) { try { String apiUrl = "http://" + mediamtxHost + ":9997/v2"; mediaClient.kick(apiUrl, sessionId); return true; } catch (Exception ex) { return false; } } } ard-work/src/main/java/com/ruoyi/rongcloud/controller/RongCloudController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,34 @@ package com.ruoyi.rongcloud.controller; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.rongcloud.service.RongCloudService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @Description: * @ClassName: RongCloudController * @Author: åèä¹ * @Date: 2023å¹´07æ15æ¥16:57:56 * @Version: 1.0 **/ @RestController @Api(tags = "èäºæ¥å£") @Anonymous public class RongCloudController { @Resource RongCloudService rongCloudService; @GetMapping("getToken") @ApiOperation("è·åtoken") public AjaxResult getToken(String userId,String name) { String token = rongCloudService.getToken(userId, name); return AjaxResult.success(token); } } ard-work/src/main/java/com/ruoyi/rongcloud/domain/TokenParam.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.ruoyi.rongcloud.domain; import lombok.Data; /** * @Description: * @ClassName: TokenParam * @Author: åèä¹ * @Date: 2023å¹´07æ15æ¥16:54:39 * @Version: 1.0 **/ @Data public class TokenParam { String userId; String name; } ard-work/src/main/java/com/ruoyi/rongcloud/service/Impl/RongCloudServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,47 @@ package com.ruoyi.rongcloud.service.Impl; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.rongcloud.domain.TokenParam; import com.ruoyi.rongcloud.service.RongCloudService; import com.ruoyi.system.mapper.SysConfigMapper; import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.utils.forest.RongCloudClient; import okhttp3.FormBody; import okhttp3.RequestBody; import org.apache.commons.codec.digest.DigestUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Date; /** * @Description: * @ClassName: RongCloudServiceImpl * @Author: åèä¹ * @Date: 2023å¹´07æ15æ¥16:49:12 * @Version: 1.0 **/ @Service public class RongCloudServiceImpl implements RongCloudService { @Resource RongCloudClient rongCloudClient; @Resource ISysConfigService iSysConfigService; @Override public String getToken(String userId,String name) { // String appKey="6tnym11s1h717"; // String appSecret="IwcGk2flZr"; String rongyunApiUrl = iSysConfigService.selectConfigByKey("rongyun"); String appKey = iSysConfigService.selectConfigByKey("RongCloudAppKey"); String appSecret = iSysConfigService.selectConfigByKey("RongCloudAppSecret"); TokenParam param=new TokenParam(); param.setUserId(userId); param.setName(name); String Nonce = String.valueOf(Math.random()).split("\\.")[1]; String Timestamp = String.valueOf(new Date().getTime()); String Signature = DigestUtils.sha1Hex(appSecret + Nonce + Timestamp);//App Secret + Nonce + Timestamp String token = rongCloudClient.getToken(rongyunApiUrl,appKey, Nonce, Timestamp, Signature, param); return token; } } ard-work/src/main/java/com/ruoyi/rongcloud/service/RongCloudService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,13 @@ package com.ruoyi.rongcloud.service; /** * @Description: * @ClassName: RongCloudService * @Author: åèä¹ * @Date: 2023å¹´07æ15æ¥16:48:36 * @Version: 1.0 **/ public interface RongCloudService { String getToken(String userId,String name); } ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java
@@ -45,8 +45,15 @@ String rtspconns(@Var("apiUrl") String apiUrl); /** * æidæ¥è¯¢rtspä¼è¯ * æsessionIdæ¥è¯¢rtspä¼è¯ */ @Get("{apiUrl}/rtspsessions/get/{sessionId}") String getRtspsessionById(@Var("apiUrl") String apiUrl, @Var("sessionId") String sessionId); /** * æsessionIdå é¤rtspä¼è¯ */ @Post("{apiUrl}/rtspsessions/kick/{sessionId}") String kick(@Var("apiUrl") String apiUrl, @Var("sessionId") String sessionId); } ard-work/src/main/java/com/ruoyi/utils/forest/RongCloudClient.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,23 @@ package com.ruoyi.utils.forest; import com.dtflys.forest.annotation.BaseRequest; import com.dtflys.forest.annotation.Body; import com.dtflys.forest.annotation.Post; import com.dtflys.forest.annotation.Var; import com.ruoyi.rongcloud.domain.TokenParam; @BaseRequest( baseURL = "{rongyunApiUrl}", sslProtocol = "TLS" ) public interface RongCloudClient { @Post(url = "/user/getToken.json", headers = { "App-Key:{AppKey}", "Nonce:{Nonce}", "Timestamp:{Timestamp}", "Signature:{Signature}", }) public String getToken(@Var("rongyunApiUrl") String rongyunApiUrl,@Var("AppKey") String AppKey, @Var("Nonce") String Nonce, @Var("Timestamp") String Timestamp, @Var("Signature") String Signature, @Body TokenParam param); } ard-work/src/main/java/com/ruoyi/utils/tools/ArdTool.java
@@ -5,6 +5,7 @@ import javax.annotation.Resource; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalTime; import java.util.*; @@ -87,4 +88,37 @@ return 1; } } /** * æä»¶å¤§å°æºè½è½¬æ¢ * ä¼å°æä»¶å¤§å°è½¬æ¢ä¸ºæå¤§æ»¡è¶³åä½ * @param sizeï¼æä»¶å¤§å°ï¼åä½ä¸ºBï¼ * @return æä»¶å¤§å° */ public static String formatFileSize(Long size) { String sizeName = null; if (1024 * 1024 > size && size >= 1024) { sizeName = String.format("%.2f", size.doubleValue() / 1024) + "KB"; } else if (1024 * 1024 * 1024 > size && size >= 1024 * 1024) { sizeName = String.format("%.2f", size.doubleValue() / (1024 * 1024)) + "MB"; } else if (size >= 1024 * 1024 * 1024) { sizeName = String.format("%.2f", size.doubleValue() / (1024 * 1024 * 1024)) + "GB"; } else { sizeName = size.toString() + "B"; } return sizeName; } /** * æä»¶å¤§å°æºè½è½¬æ¢ * ä¼å°æä»¶å¤§å°è½¬æ¢ä¸ºæå¤§æ»¡è¶³åä½ * @param sizeï¼æä»¶å¤§å°ï¼åä½ä¸ºBï¼ * @return æä»¶å¤§å° */ public static String readableFileSize(long size) { if (size <= 0) { return "0"; } final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"}; int digitGroups = (int) (Math.log10(size) / Math.log10(1024)); return new DecimalFormat("#,###.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups]; } }