当前位置: 首页 > news >正文

TensorFlow音频分类修复

原先传wav格式,后来发现前端生成的wav格式不完整   后端改mp3  其实是mp3和wav都可以接收 

前端MP3和wav格式不正确,导致可以接收,但都无法计算时长

该文作废,可能导致音频分类不准确

修复TensorFlow放到生产后报错问题-CSDN博客

依赖

  <dependency><groupId>org.tensorflow</groupId><artifactId>tensorflow-core-api</artifactId><version>0.4.2</version></dependency><dependency><groupId>org.tensorflow</groupId><artifactId>tensorflow-core-api</artifactId><version>0.4.2</version><classifier>linux-x86_64</classifier></dependency><dependency><groupId>org.tensorflow</groupId><artifactId>tensorflow-core-api</artifactId><version>0.4.2</version><classifier>windows-x86_64</classifier></dependency><!-- https://mvnrepository.com/artifact/com.googlecode.soundlibs/jlayer --><dependency><groupId>com.googlecode.soundlibs</groupId><artifactId>jlayer</artifactId><version>1.0.1.4</version></dependency>

TensorFlow工具类

package com.ruoyi.webapp.tensorflow;import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.sound.sampled.*;
import java.io.*;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.tensorflow.*;
import org.tensorflow.ndarray.*;
import org.tensorflow.proto.framework.MetaGraphDef;
import org.tensorflow.proto.framework.SignatureDef;
import org.tensorflow.types.TFloat32;
import com.google.protobuf.InvalidProtocolBufferException;import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.BitstreamException;
import javazoom.jl.decoder.Decoder;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.decoder.SampleBuffer;
import javazoom.jl.decoder.Header;@Component
public class YamnetUtils3 {private static final int SAMPLE_RATE = 16000;private static final int FRAME_SIZE_IN_MS = 96;private static final int HOP_SIZE_IN_MS = 48;//private static final String MODEL_PATH = "C:\\Users\\user\\Downloads\\archive";private static final String MODEL_PATH = "/usr/local/develop/archive"; // TensorFlow 模型路径private static Map<String, SignatureDef> signatureDefMap;static {try (SavedModelBundle savedModelBundle = SavedModelBundle.load(MODEL_PATH, "serve")) {signatureDefMap = MetaGraphDef.parseFrom(savedModelBundle.metaGraphDef().toByteArray()).getSignatureDefMap();} catch (InvalidProtocolBufferException e) {e.printStackTrace();}}private static final SignatureDef modelSig = signatureDefMap.get("serving_default");private static final String inputTensorName = modelSig.getInputsMap().get("waveform").getName();private static final String outputTensorName = modelSig.getOutputsMap().get("output_0").getName();private static Map<String, String> map = new ConcurrentHashMap<>();static {//String csvFile = "C:\\Users\\user\\Downloads\\archive\\assets\\yamnet_class_map.csv";String csvFile = "/usr/local/develop/archive/assets/yamnet_class_map.csv";try {List<String> lines = Files.readAllLines(Paths.get(csvFile));for (String line : lines) {String[] values = line.split(",");map.put(values[0], values[2]);}} catch (IOException e) {e.printStackTrace();}}public String classifyAudio(MultipartFile file) throws IOException, UnsupportedAudioFileException {// Convert the MP3 file to a supported format (WAV)File wavFile = convertMp3ToWav(file);// Process the converted filereturn yamnetPare(wavFile);}private File convertMp3ToWav(MultipartFile file) throws IOException {File tempFile = File.createTempFile("temp", ".wav");File mp3File = File.createTempFile("temp", ".mp3");file.transferTo(mp3File);try (FileInputStream mp3Stream = new FileInputStream(mp3File);FileOutputStream wavStream = new FileOutputStream(tempFile)) {Bitstream bitstream = new Bitstream(mp3Stream);Decoder decoder = new Decoder();// Write WAV headerwriteWavHeader(wavStream, 0, 1, SAMPLE_RATE, 16);Header header;while ((header = bitstream.readFrame()) != null) {SampleBuffer output = (SampleBuffer) decoder.decodeFrame(header, bitstream);short[] samples = output.getBuffer();for (short sample : samples) {wavStream.write(shortToBytes(sample));}bitstream.closeFrame();}// Update WAV header with data sizeupdateWavHeader(tempFile);} catch (Exception e) {throw new IOException("Failed to convert MP3 to WAV", e);}return tempFile;}private void writeWavHeader(OutputStream out, long totalAudioLen, int channels, long sampleRate, int bitDepth) throws IOException {long totalDataLen = totalAudioLen + 36;long byteRate = sampleRate * channels * bitDepth / 8;byte[] header = new byte[44];header[0] = 'R';  // RIFF/WAVE headerheader[1] = 'I';header[2] = 'F';header[3] = 'F';header[4] = (byte) (totalDataLen & 0xff);header[5] = (byte) ((totalDataLen >> 8) & 0xff);header[6] = (byte) ((totalDataLen >> 16) & 0xff);header[7] = (byte) ((totalDataLen >> 24) & 0xff);header[8] = 'W';header[9] = 'A';header[10] = 'V';header[11] = 'E';header[12] = 'f';  // 'fmt ' chunkheader[13] = 'm';header[14] = 't';header[15] = ' ';header[16] = 16;  // 4 bytes: size of 'fmt ' chunkheader[17] = 0;header[18] = 0;header[19] = 0;header[20] = 1;  // format = 1header[21] = 0;header[22] = (byte) channels;header[23] = 0;header[24] = (byte) (sampleRate & 0xff);header[25] = (byte) ((sampleRate >> 8) & 0xff);header[26] = (byte) ((sampleRate >> 16) & 0xff);header[27] = (byte) ((sampleRate >> 24) & 0xff);header[28] = (byte) (byteRate & 0xff);header[29] = (byte) ((byteRate >> 8) & 0xff);header[30] = (byte) ((byteRate >> 16) & 0xff);header[31] = (byte) ((byteRate >> 24) & 0xff);header[32] = (byte) (2 * 16 / 8);  // block alignheader[33] = 0;header[34] = (byte) bitDepth;  // bits per sampleheader[35] = 0;header[36] = 'd';header[37] = 'a';header[38] = 't';header[39] = 'a';header[40] = (byte) (totalAudioLen & 0xff);header[41] = (byte) ((totalAudioLen >> 8) & 0xff);header[42] = (byte) ((totalAudioLen >> 16) & 0xff);header[43] = (byte) ((totalAudioLen >> 24) & 0xff);out.write(header, 0, 44);}private void updateWavHeader(File wavFile) throws IOException {RandomAccessFile wavRAF = new RandomAccessFile(wavFile, "rw");wavRAF.seek(4);wavRAF.write(intToBytes((int) (wavRAF.length() - 8)));wavRAF.seek(40);wavRAF.write(intToBytes((int) (wavRAF.length() - 44)));wavRAF.close();}private byte[] intToBytes(int value) {return new byte[]{(byte) (value & 0xFF),(byte) ((value >> 8) & 0xFF),(byte) ((value >> 16) & 0xFF),(byte) ((value >> 24) & 0xFF)};}private byte[] shortToBytes(short value) {return new byte[]{(byte) (value & 0xFF),(byte) ((value >> 8) & 0xFF)};}private FloatNdArray processAudio(File file) throws IOException, UnsupportedAudioFileException {try (AudioInputStream audioStream = AudioSystem.getAudioInputStream(file)) {AudioFormat format = audioStream.getFormat();if (format.getSampleRate() != SAMPLE_RATE || format.getChannels() != 1) {System.out.println("Warning: Audio must be 16kHz mono. Consider preprocessing.");}int frameSize = (int) (SAMPLE_RATE * FRAME_SIZE_IN_MS / 1000);int hopSize = (int) (SAMPLE_RATE * HOP_SIZE_IN_MS / 1000);byte[] buffer = new byte[frameSize * format.getFrameSize()];short[] audioSamples = new short[frameSize];List<Float> floatList = new ArrayList<>();while (true) {int bytesRead = audioStream.read(buffer);if (bytesRead == -1) {break;}for (int i = 0; i < bytesRead / format.getFrameSize(); i++) {audioSamples[i] = (short) ((buffer[i * 2] & 0xFF) | (buffer[i * 2 + 1] << 8));}float[] floats = normalizeAudio(audioSamples);for (float aFloat : floats) {floatList.add(aFloat);}System.arraycopy(audioSamples, hopSize, audioSamples, 0, frameSize - hopSize);}float[] floatArray = new float[floatList.size()];for (int i = 0; i < floatList.size(); i++) {floatArray[i] = floatList.get(i);}return StdArrays.ndCopyOf(floatArray);}}private float[] normalizeAudio(short[] frame) {float[] normalizedFrame = new float[frame.length];for (int i = 0; i < frame.length; i++) {normalizedFrame[i] = frame[i] / 32768f;}return normalizedFrame;}private String yamnetPare(File file) throws IOException, UnsupportedAudioFileException {FloatNdArray floatNdArray = processAudio(file);TFloat32 tFloat32 = TFloat32.tensorOf(floatNdArray);try (SavedModelBundle savedModelBundle = SavedModelBundle.load(MODEL_PATH, "serve")) {try (Session session = savedModelBundle.session()) {List<Tensor> run = session.runner().feed(inputTensorName, tFloat32).fetch(outputTensorName).run();Tensor tensor = run.get(0);Shape shape = tensor.shape();System.out.println(shape + "--------------------------------------------------");String key = String.valueOf(shape.asArray()[0]);String value = map.get(key);return value;}}}
}

文件接口

 //记录文件@PostMapping("/reportUpload")//@RequireVip//睡眠监测时 文件上传接口public AjaxResult reportUpload(MultipartFile file) throws IOException {try {//获取文件名String originalFilename = file.getOriginalFilename();//获取时长秒//String wavDuration = getWavDuration(file);//String wavDuration = getWavDuration3(file);//String wavDuration = getWavDuration55(file);String filePath = RuoYiConfig.getUploadPath();///usr/local/nginx/html/upload/upload//上传并返回新文件路径String fileName = FileUploadUtils.upload(filePath, file);//获取音频类型//String s = yamnetUtils2.yamnetPare(file);String s = yamnetUtils3.classifyAudio(file);//获取时长秒//String wavDuration =getWavDuration(fileName);getMp3DurationString wavDuration =getMp3Duration(fileName);if(!StringUtils.isEmpty(s)){if (!s.equals("Speech") && !s.equals("Snoring") && !s.equals("Cough")) {s = "Other";}TReportFile tReportFile=new TReportFile();tReportFile.setUid(getLoginUser().getUserId());tReportFile.setFileType(s);tReportFile.setLengths(wavDuration);tReportFile.setFilePath(fileName);//tReportFile.setCreateTime(new Date());tReportFileService.insertTReportFile(tReportFile);}return success();}catch (Exception e){e.printStackTrace();return error();}}

 //获取wav文件时长private String getWavDuration(String relativeFilePath) {String basePath = "/usr/local/nginx/html/upload";if (relativeFilePath.startsWith("/profile")) {relativeFilePath = relativeFilePath.substring(8);}String fullPath = basePath + relativeFilePath;File file = new File(fullPath);if (!file.exists()) {return "File not found";}try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file)) {AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(file);long frameLength = audioInputStream.getFrameLength();float frameRate = fileFormat.getFormat().getFrameRate();float durationInSeconds = frameLength / frameRate;return Math.round(durationInSeconds) + "s";} catch (UnsupportedAudioFileException | IOException e) {e.printStackTrace();return "Error";}}//获取Mp3文件时长public static String getMp3Duration(String relativeFilePath) {String basePath = "/usr/local/nginx/html/upload";if (relativeFilePath.startsWith("/profile")) {relativeFilePath = relativeFilePath.substring(8);}String fullPath = basePath + relativeFilePath;File file = new File(fullPath);if (!file.exists()) {return "File not found";}try (FileInputStream fileInputStream = new FileInputStream(file)) {Bitstream bitstream = new Bitstream(fileInputStream);Header header;int totalFrames = 0;float totalDuration = 0;while ((header = bitstream.readFrame()) != null) {totalDuration += header.ms_per_frame();totalFrames++;bitstream.closeFrame();}float durationInSeconds = totalDuration / 1000.0f;return Math.round(durationInSeconds) + "s";} catch (IOException | BitstreamException e) {e.printStackTrace();return "Error";}}

相关文章:

TensorFlow音频分类修复

原先传wav格式,后来发现前端生成的wav格式不完整 后端改mp3 其实是mp3和wav都可以接收 前端MP3和wav格式不正确,导致可以接收,但都无法计算时长 该文作废,可能导致音频分类不准确 修复TensorFlow放到生产后报错问题-CSDN博客 依赖 <dependency><groupId>or…...

C#学习系列之ListView垂直滚动

C#学习系列之ListView垂直滚动 前言垂直滚动总结 前言 当ListView中不断增加新内容&#xff0c;经常是纵向滚动。 垂直滚动 这个是关键&#xff1a;<VirtualizingStackPanel/> <ListView.ItemsPanel><ItemsPanelTemplate><VirtualizingStackPanel/>&…...

MySQL 常用函数总结

MySQL 提供了丰富的内置函数&#xff0c;用于在查询中进行各种计算、字符串处理、日期和时间操作等。这些函数可以帮助我们更有效地从数据库中检索和处理数据。下面将总结一些 MySQL 中常用的函数及其用法。 1. 数值函数 1.1 ROUND() ROUND() 函数用于对数值进行四舍五入操作…...

SpingBoot快速入门下

响应HttpServietResponse 介绍 将ResponseBody 加到Controller方法/类上 作用&#xff1a;将方法返回值直接响应&#xff0c;如果返回值是 实体对象/集合&#xff0c;将会自动转JSON格式响应 RestController Controller ResponseBody; 一般响应 统一响应 在实际开发中一般…...

什么是symbol?

在ES6&#xff08;ECMAScript 2015&#xff09;中&#xff0c;Symbol是一种新的基本数据类型&#xff0c;它的主要特点是独一无二且不可变。以下是关于ES6中Symbol的详细解释&#xff1a; 定义与特性&#xff1a; Symbol是ES6引入的一种基本数据类型&#xff0c;用于表示独一无…...

Tailwind CSS 响应式设计实战指南

title: Tailwind CSS 响应式设计实战指南 date: 2024/6/13 updated: 2024/6/13 author: cmdragon excerpt: 这篇文章介绍了如何运用Tailwind CSS框架创建响应式网页设计&#xff0c;涵盖博客、电商网站及企业官网的布局实例&#xff0c;包括头部导航、内容区域、侧边栏、页脚…...

如何把模糊的图片修复变清晰,怎么做?有那些方法?

模糊照片怎么修复清晰&#xff1f;有些照片可能会因为保存不当或其他原因而变得模糊&#xff0c;这些照片删掉又觉得可惜&#xff0c;那么如何让这些照片焕然一新呢&#xff1f;今天就给大家分享几种可以将这些珍贵的模糊照片修复为高清照片的方法。接下来&#xff0c;给大家演…...

思科路由器密码恢复方法

1.密码恢复原理 Cisco路由器保存了几种不同的配置参数&#xff0c;并存放在不同的内存模块中。 Cisco系列路由器的内存有&#xff1a;ROM&#xff0c;闪存&#xff08;Flashmemory&#xff09;,RAM&#xff0c;不可变RAM和动态内存&#xff08;DRAM&#xff09;等5种。 一般情况…...

HTML某联招聘

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <!-- 一些其他说明&#xff1a; 不写form的话&#xff0c;表单内容也是可以正常显示的&#xff0…...

第一百一十六节 Java 面向对象设计 - Java 终止块

Java 面向对象设计 - Java 终止块 ​try ​块也可以有零个或一个​ finally​ 块。 ​finally ​块总是与 ​try ​块一起使用。 语法 使用 ​finally​ 块的语法是 finally {// Code for finally block }​finally​ 块以关键字 ​finally​ 开始&#xff0c;后面紧跟一对…...

YOLOv10改进 | 注意力篇 | YOLOv10引入YOLO-Face提出的SEAM注意力机制优化物体遮挡检测

1. SEAM介绍 1.1 摘要:近年来,基于深度学习的人脸检测算法取得了长足的进步。 这些算法通常可以分为两类,即像 Faster R-CNN 这样的两级检测器和像 YOLO 这样的一级检测器。 由于精度和速度之间具有更好的平衡,一级探测器已广泛应用于许多应用中。 在本文中,我们提出了一…...

问题解决:Problem exceeding maximum token in azure openai (with java)

问题背景&#xff1a; Im doing a chat that returns queries based on the question you ask it in reference to a specific database. For this I use azure openai and Java in Spring Boot. 我正在开发一个聊天功能&#xff0c;该功能根据您针对特定数据库的提问返回查询…...

eNSP学习——OSPF在帧中继网络中的配置

目录 主要命令 原理概述 实验目的 实验场景 实验拓扑 实验编址 实验步骤 1、基本配置 2、在帧中继上搭建OSPF网络 主要命令 //检查帧中继的虚电路状态 display fr pvc-info//检查帧中继的映射表 display fr map-info//手工指定OSPF邻居,采用单播方式发送报文 [R1]os…...

PHP转Go系列 | 条件循环的使用姿势

大家好&#xff0c;我是码农先森。 条件 在 PHP 语言中条件控制语句&#xff0c;主要有 if、elseif、else 和 switch 语句 // if、elseif、else 语句 $word "a"; if ($word "a") {echo "a"; } elseif ($word "b") {echo "b&…...

八大经典排序算法

前言 本片博客主要讲解一下八大排序算法的思想和排序的代码 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;排序_普通young man的博客-CSDN博客 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 目录 …...

【LeetCode热题 100】三数之和

leetcode原地址&#xff1a;https://leetcode.cn/problems/3sum/description 描述 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和…...

【深度学习驱动流体力学】完整配置安装 OpenFOAM 及其所需的ThirdParty与QT5工具

OpenFOAM 简介 OpenFOAM(Open Field Operation and Manipulation)是一个领先的开源计算流体动力学(CFD)软件包,由 OpenFOAM Foundation 开发和维护。作为一个高度模块化和可扩展的软件工具箱,OpenFOAM 支持模拟多种物理现象,包括流体流动、传热、混合、燃烧、声学等。由…...

YOLOv10改进 | Neck | 添加双向特征金字塔BiFPN【含二次独家创新】

&#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录&#xff1a;《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40篇内容&#xff0c;内含各种Head检测头、损失函数Loss、B…...

PostgreSQL源码分析——pg_basebackup

涉及到的代码主要在src/backend/replication以及bin/pg_basebackup中。 我们知道pg_basebackup是一个进行基础备份的工具&#xff0c;除了使用这个工具&#xff0c;还可以用底层API的方式进行基础备份&#xff0c;主要过程如下&#xff1a; 连接到数据库执行select pg_start_…...

QT基础 - 常见图表绘制

目录 零. 前言 一. 添加模块 折线图 三. 树状图 四. 饼图 五. 堆叠柱状图 六. 百分比柱状图 七. 散点图和光滑曲线图 散点图 光滑曲线图 零. 前言 Qt Charts 是 Qt 框架的一个模块&#xff0c;用于创建各种类型的图表和数据可视化。它为开发者提供了一套功能强大的工…...

LLM大模型开发实战:6个爆款开源项目,小白也能轻松入门!

本文介绍了6个GitHub上的热门LLM&#xff08;大型语言模型&#xff09;开源项目&#xff0c;包括Datawhale的"LLM-Universe"和"LLM-Cookbook"、微软的"Generative AI for Beginners"、mlabonne的"LLM-Course"、liguodongiot的"LL…...

拉丝机在紧固件生产中的作用与工艺流程_6月FES上海紧固件展

2026第十六届上海紧固件专业展将于6月24日至26日在国家会展中心&#xff08;上海&#xff09;举行。本届展会由上海上搜展览与华人螺丝网联合打造&#xff0c;并获得行业权威机构支持&#xff0c;整体展出规模约70,000平方米&#xff0c;预计汇聚1,400余家参展企业和25,000名专…...

从Tcl脚本到实战:用Innovus自动化完成数字IC后端设计的5个高效技巧

从Tcl脚本到实战&#xff1a;用Innovus自动化完成数字IC后端设计的5个高效技巧 在数字IC后端设计领域&#xff0c;效率提升往往意味着项目周期的缩短和设计质量的提高。对于已经掌握Innovus基础操作的中级工程师而言&#xff0c;如何从手动点击界面过渡到自动化脚本驱动的工作流…...

Python与Matlab双剑合璧:高效解析XJTU-SY轴承数据集实战指南

1. 为什么选择Python和Matlab处理XJTU-SY轴承数据 轴承故障诊断是工业设备健康管理的重要环节&#xff0c;而XJTU-SY轴承数据集作为国内知名的公开数据集&#xff0c;包含了多种工况下的全寿命周期振动数据。面对这样的工程数据集&#xff0c;Python和Matlab各有优势。我在实际…...

Emby Premiere完全免费解锁终极教程:简单三步享受高级媒体服务器功能

Emby Premiere完全免费解锁终极教程&#xff1a;简单三步享受高级媒体服务器功能 【免费下载链接】emby-unlocked Emby with the premium Emby Premiere features unlocked. 项目地址: https://gitcode.com/gh_mirrors/em/emby-unlocked 你是否曾经为Emby Premiere的高级…...

手把手教你优化SiC MOSFET模块:从铜带键合到双面散热的5个关键技术

SiC MOSFET功率模块封装优化实战&#xff1a;五大关键技术深度解析 在电力电子领域&#xff0c;碳化硅(SiC)MOSFET功率模块正逐步取代传统硅基IGBT&#xff0c;成为高效率、高功率密度应用的首选。然而&#xff0c;要充分发挥SiC材料的性能优势&#xff0c;封装技术面临前所未…...

通义千问3-VL-Reranker-8B新手教程:零基础学会混合检索排序

通义千问3-VL-Reranker-8B新手教程&#xff1a;零基础学会混合检索排序 1. 认识这个强大的多模态排序工具 想象一下&#xff0c;你正在管理一个包含文字、图片和视频的庞大数据库。当用户搜索"户外运动装备"时&#xff0c;系统返回了100个结果——有些是产品描述文…...

Qwen3-ASR-1.7B语音识别实战:科研访谈录音转文本+主题自动聚类

Qwen3-ASR-1.7B语音识别实战&#xff1a;科研访谈录音转文本主题自动聚类 想象一下这个场景&#xff1a;你刚刚结束了一场长达两小时的深度科研访谈&#xff0c;录音文件静静地躺在你的电脑里。接下来&#xff0c;你需要逐字逐句地听录音、做笔记、整理成文字稿&#xff0c;然…...

Face3D.ai Pro多场景落地:VR会议、元宇宙社交、AI主播协同方案

Face3D.ai Pro多场景落地&#xff1a;VR会议、元宇宙社交、AI主播协同方案 1. 引言&#xff1a;从2D照片到3D数字人的技术突破 想象一下&#xff0c;你只需要上传一张普通的自拍照&#xff0c;就能瞬间获得一个精细的3D数字人形象。这个数字人不仅外形逼真&#xff0c;还能在…...

【进阶指南】VSCode + Clang-Format:从零定制你的专属代码风格(130+配置项实战解析)

1. 为什么需要定制代码风格&#xff1f; 当你第一次接触代码格式化工具时&#xff0c;可能会觉得默认配置已经足够好用。但当你参与过几个团队项目后&#xff0c;就会发现统一的代码风格有多重要。我曾经接手过一个遗留项目&#xff0c;里面混杂着五种不同的缩进风格——有用制…...