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

TwelveMonkeys ImageIO:Java图像格式处理的终极解决方案

TwelveMonkeys ImageIO:Java图像格式处理的终极解决方案

【免费下载链接】TwelveMonkeysTwelveMonkeys ImageIO: Additional plug-ins and extensions for Java's ImageIO项目地址: https://gitcode.com/gh_mirrors/tw/TwelveMonkeys

TwelveMonkeys ImageIO 是 Java 平台上一套强大的图像格式扩展库,为开发者提供了超越标准 JDK 的图像格式支持。在当今多元化的图像处理需求中,Java 内置的 ImageIO 框架虽然强大,但对于许多专业格式的支持却有限。TwelveMonkeys ImageIO 填补了这一空白,让 Java 开发者能够轻松处理从专业设计到历史遗留格式的各种图像文件。

🚀 快速入门:5分钟搭建你的图像处理环境

项目依赖配置

要开始使用 TwelveMonkeys ImageIO,首先需要在你的项目中添加相应的依赖。项目采用模块化设计,你可以根据实际需求选择特定的格式插件。

Maven 配置示例:

<dependencies> <!-- 核心依赖 --> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-core</artifactId> <version>3.13.1</version> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-metadata</artifactId> <version>3.13.1</version> </dependency> <!-- 格式插件(按需选择) --> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-jpeg</artifactId> <version>3.13.1</version> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-tiff</artifactId> <version>3.13.1</version> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-psd</artifactId> <version>3.13.1</version> </dependency> </dependencies>

Gradle 配置示例:

dependencies { implementation 'com.twelvemonkeys.imageio:imageio-core:3.13.1' implementation 'com.twelvemonkeys.imageio:imageio-metadata:3.13.1' implementation 'com.twelvemonkeys.imageio:imageio-jpeg:3.13.1' implementation 'com.twelvemonkeys.imageio:imageio-tiff:3.13.1' }

基本图像读取与写入

安装完成后,使用方式与标准 ImageIO 完全兼容:

import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; public class BasicImageIOExample { public static void main(String[] args) { try { // 读取图像 - 自动识别格式 File inputFile = new File("image.psd"); BufferedImage image = ImageIO.read(inputFile); // 处理图像... // 保存为不同格式 File outputFile = new File("output.jpg"); ImageIO.write(image, "JPEG", outputFile); System.out.println("图像处理完成!"); } catch (Exception e) { e.printStackTrace(); } } }

插件自动发现机制

TwelveMonkeys ImageIO 最巧妙的设计之一是其自动发现机制。插件通过 Java 的 Service Provider Interface (SPI) 自动注册到 ImageIO 框架中。这意味着:

  1. 零配置使用:只需将 JAR 文件放入 classpath
  2. 无缝集成:无需修改现有代码
  3. 优先级管理:TwelveMonkeys 插件会自动优先于 JDK 内置插件

验证插件是否成功加载:

Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG"); while (readers.hasNext()) { ImageReader reader = readers.next(); System.out.println("找到 JPEG 阅读器: " + reader.getClass().getName()); }

📊 全面格式支持:超越 JDK 的图像处理能力

TwelveMonkeys ImageIO 支持超过 20 种图像格式,覆盖了从专业设计到历史遗留的各种需求。

主要支持的图像格式

格式类型支持格式读取写入特点说明
专业设计格式PSD (Photoshop)支持图层和元数据
WebP-Google 现代图像格式
HDR (RGBE)-高动态范围图像
文档与矢量SVG-可缩放矢量图形
WMF-Windows 图元文件
遗留与专业格式TIFF/BigTIFF支持多页和压缩
IFFAmiga/EA 交换格式
ICNSApple 图标格式
DDS-DirectX 纹理格式
其他实用格式SGI-Silicon Graphics 图像
TGATruevision TGA
PCX/DCX-ZSoft Paintbrush
PNM 系列NetPBM 便携式格式
XWD-X11 窗口转储

增强的 JDK 内置格式支持

除了新增格式,TwelveMonkeys 还显著增强了 JDK 内置格式的功能:

  • JPEG:更好的 EXIF 元数据处理、ICC 配置文件支持
  • BMP:支持更多子格式和压缩方式
  • TIFF:更好的 BigTIFF 支持和元数据处理

实际应用场景示例

场景一:处理专业设计文件

// 读取 Photoshop PSD 文件 File psdFile = new File("design.psd"); BufferedImage psdImage = ImageIO.read(psdFile); // 保存为 Web 友好的格式 File webFile = new File("design.webp"); ImageIO.write(psdImage, "WebP", webFile);

场景二:批量转换历史档案图像

// 批量转换 IFF 格式图像 File iffDir = new File("archive/iff_files"); for (File iffFile : iffDir.listFiles((dir, name) -> name.endsWith(".iff"))) { BufferedImage image = ImageIO.read(iffFile); File pngFile = new File("converted/" + iffFile.getName() + ".png"); ImageIO.write(image, "PNG", pngFile); }

🔧 高级功能:专业级图像处理技巧

Adobe 剪切路径支持

TwelveMonkeys ImageIO 提供了对 Photoshop 剪切路径的原生支持,这在处理专业设计素材时非常有用:

import com.twelvemonkeys.imageio.path.Paths; import javax.imageio.ImageIO; import javax.imageio.stream.ImageInputStream; import java.io.File; public class ClippingPathExample { public static void main(String[] args) { try (ImageInputStream stream = ImageIO.createImageInputStream( new File("image_with_path.jpg"))) { // 读取并应用剪切路径 BufferedImage clippedImage = Paths.readClipped(stream); // 处理剪切后的图像 // clippedImage 现在只包含路径内的区域 System.out.println("剪切图像尺寸: " + clippedImage.getWidth() + "x" + clippedImage.getHeight()); } catch (Exception e) { e.printStackTrace(); } } }

图:TwelveMonkeys ImageIO 支持读取包含剪切路径的 JPEG 图像,保留专业设计意图

高质量图像重采样

项目内置的ResampleOp类提供了多种高质量重采样算法:

import com.twelvemonkeys.image.ResampleOp; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; public class ResampleExample { public BufferedImage resizeImage(BufferedImage original, int targetWidth, int targetHeight) { // 使用 Lanczos 滤波器进行高质量重采样 BufferedImageOp resampler = new ResampleOp( targetWidth, targetHeight, ResampleOp.FILTER_LANCZOS ); return resampler.filter(original, null); } public BufferedImage resizeWithAspectRatio(BufferedImage original, int maxDimension) { int width = original.getWidth(); int height = original.getHeight(); if (width > height) { return resizeImage(original, maxDimension, (int) (height * ((double) maxDimension / width))); } else { return resizeImage(original, (int) (width * ((double) maxDimension / height)), maxDimension); } } }

扩散抖动处理

对于需要将真彩色图像转换为索引颜色的场景,项目提供了高质量的抖动算法:

import com.twelvemonkeys.image.DiffusionDither; public class DitherExample { public BufferedImage convertToIndexed(BufferedImage rgbImage) { // 使用 Floyd-Steinberg 误差扩散抖动 BufferedImageOp ditherer = new DiffusionDither(); return ditherer.filter(rgbImage, null); } }

处理损坏的图像文件

在实际应用中,经常需要处理不完整或损坏的图像文件。TwelveMonkeys ImageIO 提供了更优雅的错误处理机制:

public class RobustImageReader { public BufferedImage readImageSafely(File file) { try (ImageInputStream input = ImageIO.createImageInputStream(file)) { Iterator<ImageReader> readers = ImageIO.getImageReaders(input); if (!readers.hasNext()) { throw new IllegalArgumentException("不支持的文件格式: " + file); } ImageReader reader = readers.next(); try { reader.setInput(input); // 获取图像尺寸而不完全加载 int width = reader.getWidth(0); int height = reader.getHeight(0); // 创建目标图像 ImageTypeSpecifier imageType = reader.getRawImageType(0); BufferedImage image = imageType.createBufferedImage(width, height); // 设置目标,即使文件损坏也能获取部分数据 ImageReadParam param = reader.getDefaultReadParam(); param.setDestination(image); try { return reader.read(0, param); } catch (IOException e) { // 文件可能损坏,但我们已经有了部分图像数据 System.err.println("警告:图像文件可能损坏,返回部分数据"); return image; } } finally { reader.dispose(); } } catch (Exception e) { throw new RuntimeException("无法读取图像文件", e); } } }

🌐 部署与集成:生产环境最佳实践

Web 应用程序部署

在 Servlet 容器中部署 ImageIO 插件需要特殊处理,因为 ImageIO 的插件注册是 VM 全局的:

<!-- web.xml 配置 --> <web-app> <listener> <display-name>ImageIO 服务提供者加载器/卸载器</display-name> <listener-class> com.twelvemonkeys.servlet.image.IIOProviderContextListener </listener-class> </listener> </web-app>

Maven 依赖配置:

<dependency> <groupId>com.twelvemonkeys.servlet</groupId> <artifactId>servlet</artifactId> <version>3.13.1</version> </dependency>

构建可执行 JAR 文件

当创建包含所有依赖的 "fat" JAR 时,需要正确处理 SPI 服务文件:

<!-- Maven Shade 插件配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <phase>package</phase> <goals><goal>shade</goal></goals> <configuration> <transformers> <!-- 合并 SPI 服务文件 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <!-- 保留清单信息 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/> </transformers> </configuration> </execution> </executions> </plugin>

性能优化技巧

  1. 内存管理:对于大图像文件,使用流式处理
public class MemoryEfficientReader { public void processLargeImage(File largeFile) throws IOException { try (ImageInputStream stream = ImageIO.createImageInputStream(largeFile)) { ImageReader reader = ImageIO.getImageReaders(stream).next(); reader.setInput(stream); // 分块读取大图像 ImageReadParam param = reader.getDefaultReadParam(); param.setSourceSubsampling(2, 2, 0, 0); // 降低采样率 // 或者指定读取区域 Rectangle region = new Rectangle(0, 0, 1000, 1000); param.setSourceRegion(region); BufferedImage tile = reader.read(0, param); // 处理图像块... } } }
  1. 并发处理:多线程图像处理
public class ConcurrentImageProcessor { private final ExecutorService executor = Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() ); public void processBatch(List<File> imageFiles) { List<Future<BufferedImage>> futures = new ArrayList<>(); for (File file : imageFiles) { futures.add(executor.submit(() -> { return ImageIO.read(file); })); } // 处理结果... } }

🛠️ 故障排除与调试指南

常见问题解决方案

问题1:插件未加载

// 诊断代码 public class PluginDiagnostic { public static void checkPlugins() { System.out.println("=== 已注册的 ImageReader ==="); String[] formatNames = ImageIO.getReaderFormatNames(); for (String format : formatNames) { System.out.println("格式: " + format); Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(format); while (readers.hasNext()) { System.out.println(" - " + readers.next().getClass().getName()); } } // 手动扫描插件 ImageIO.scanForPlugins(); System.out.println("\n=== 扫描后重新检查 ==="); // 重新检查... } }

问题2:内存不足处理大图像

public class MemoryOptimizedImageIO { public static BufferedImage readWithMemoryLimit(File file, long maxMemory) throws IOException { try (ImageInputStream stream = ImageIO.createImageInputStream(file)) { ImageReader reader = ImageIO.getImageReaders(stream).next(); reader.setInput(stream); // 检查图像尺寸 int width = reader.getWidth(0); int height = reader.getHeight(0); int estimatedMemory = width * height * 4; // 假设 RGBA if (estimatedMemory > maxMemory) { // 使用子采样 ImageReadParam param = reader.getDefaultReadParam(); int subsample = (int) Math.ceil( Math.sqrt((double) estimatedMemory / maxMemory) ); param.setSourceSubsampling(subsample, subsample, 0, 0); return reader.read(0, param); } else { return reader.read(0); } } } }

性能监控与调优

import java.lang.management.ManagementFactory; import com.sun.management.OperatingSystemMXBean; public class ImageIOMonitor { private final OperatingSystemMXBean osBean; public ImageIOMonitor() { osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class); } public void monitorImageOperation(Runnable operation) { long startTime = System.currentTimeMillis(); long startMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); double startCpu = osBean.getProcessCpuLoad(); operation.run(); long endTime = System.currentTimeMillis(); long endMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); double endCpu = osBean.getProcessCpuLoad(); System.out.printf("操作耗时: %d ms%n", endTime - startTime); System.out.printf("内存使用: %d KB%n", (endMemory - startMemory) / 1024); System.out.printf("CPU 使用变化: %.2f%%%n", (endCpu - startCpu) * 100); } }

📈 实际案例:专业图像处理工作流

案例1:批量图像格式转换与优化

import javax.imageio.*; import javax.imageio.stream.*; import java.awt.image.*; import java.io.*; import java.util.*; public class BatchImageProcessor { private final Map<String, ImageWriter> writers = new HashMap<>(); public void processDirectory(File inputDir, File outputDir, String targetFormat) throws IOException { if (!outputDir.exists()) { outputDir.mkdirs(); } File[] imageFiles = inputDir.listFiles((dir, name) -> name.matches(".*\\.(jpg|jpeg|png|gif|bmp|tiff|psd)$")); if (imageFiles == null) return; for (File inputFile : imageFiles) { try { BufferedImage image = ImageIO.read(inputFile); if (image == null) { System.err.println("无法读取: " + inputFile.getName()); continue; } // 图像优化 BufferedImage optimized = optimizeImage(image, targetFormat); // 保存优化后的图像 File outputFile = new File(outputDir, inputFile.getName().replaceFirst("\\.[^.]+$", "." + targetFormat.toLowerCase())); saveImage(optimized, outputFile, targetFormat); System.out.println("处理完成: " + inputFile.getName() + " → " + outputFile.getName()); } catch (Exception e) { System.err.println("处理失败: " + inputFile.getName() + " - " + e.getMessage()); } } } private BufferedImage optimizeImage(BufferedImage original, String format) { // 根据目标格式应用不同的优化策略 switch (format.toUpperCase()) { case "JPEG": return optimizeForWeb(original, 0.85f); case "PNG": return optimizeForTransparency(original); case "WEBP": return optimizeForWeb(original, 0.75f); default: return original; } } private BufferedImage optimizeForWeb(BufferedImage image, float quality) { // 实现 Web 优化逻辑... return image; } private void saveImage(BufferedImage image, File outputFile, String format) throws IOException { ImageWriter writer = writers.computeIfAbsent(format, f -> { Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(f); return writers.hasNext() ? writers.next() : null; }); if (writer == null) { throw new IOException("不支持的目标格式: " + format); } try (ImageOutputStream output = ImageIO.createImageOutputStream(outputFile)) { writer.setOutput(output); ImageWriteParam param = writer.getDefaultWriteParam(); // 设置 JPEG 质量参数 if (format.equalsIgnoreCase("JPEG") && param.canWriteCompressed()) { param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(0.85f); } writer.write(null, new IIOImage(image, null, null), param); } } }

案例2:图像元数据提取与分析

import javax.imageio.*; import javax.imageio.metadata.*; import org.w3c.dom.*; public class ImageMetadataExtractor { public Map<String, Object> extractMetadata(File imageFile) throws IOException { Map<String, Object> metadata = new LinkedHashMap<>(); try (ImageInputStream stream = ImageIO.createImageInputStream(imageFile)) { Iterator<ImageReader> readers = ImageIO.getImageReaders(stream); if (!readers.hasNext()) { throw new IOException("不支持的文件格式"); } ImageReader reader = readers.next(); reader.setInput(stream); // 基本图像信息 metadata.put("format", reader.getFormatName()); metadata.put("width", reader.getWidth(0)); metadata.put("height", reader.getHeight(0)); metadata.put("numImages", reader.getNumImages(true)); // 提取元数据 IIOMetadata imageMetadata = reader.getImageMetadata(0); if (imageMetadata != null) { // 标准元数据 String[] metadataFormats = imageMetadata.getMetadataFormatNames(); for (String format : metadataFormats) { Node node = imageMetadata.getAsTree(format); metadata.putAll(parseMetadataNode(node)); } } // EXIF 数据(如果可用) extractEXIFData(reader, metadata); reader.dispose(); } return metadata; } private Map<String, Object> parseMetadataNode(Node node) { Map<String, Object> result = new HashMap<>(); // 解析元数据节点... return result; } private void extractEXIFData(ImageReader reader, Map<String, Object> metadata) { // 提取 EXIF 元数据... } public void printMetadataSummary(File imageFile) throws IOException { Map<String, Object> data = extractMetadata(imageFile); System.out.println("=== 图像元数据摘要 ==="); System.out.println("文件: " + imageFile.getName()); System.out.println("格式: " + data.get("format")); System.out.println("尺寸: " + data.get("width") + "x" + data.get("height")); // 打印其他重要元数据... } }

图:TwelveMonkeys ImageIO 能够正确处理包含 EXIF 元数据的 JPEG 图像,保留完整的拍摄信息

🎯 最佳实践总结

1. 选择合适的插件组合

根据项目需求选择必要的插件,避免不必要的依赖:

<!-- 最小化配置:仅需核心和常用格式 --> <dependencies> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-core</artifactId> <version>3.13.1</version> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-jpeg</artifactId> <version>3.13.1</version> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-png</artifactId> <version>3.13.1</version> </dependency> </dependencies>

2. 错误处理策略

public class RobustImageIO { public BufferedImage safeRead(File file) { try { return ImageIO.read(file); } catch (Exception e) { // 尝试使用备用方法 return readWithFallback(file); } } private BufferedImage readWithFallback(File file) { try (ImageInputStream stream = ImageIO.createImageInputStream(file)) { Iterator<ImageReader> readers = ImageIO.getImageReaders(stream); while (readers.hasNext()) { ImageReader reader = readers.next(); try { reader.setInput(stream); return reader.read(0); } catch (Exception ex) { // 继续尝试下一个阅读器 continue; } finally { reader.dispose(); } } throw new IOException("没有可用的阅读器"); } catch (Exception e) { throw new RuntimeException("无法读取图像文件", e); } } }

3. 性能优化建议

  • 使用 ImageInputStream:避免将整个文件加载到内存
  • 合理设置缓存大小:根据图像大小调整缓存策略
  • 批量处理优化:复用 ImageReader/ImageWriter 实例
  • 异步处理:对于大量图像处理使用线程池

4. 内存管理技巧

public class MemoryAwareImageProcessor { private static final long MAX_MEMORY = 100 * 1024 * 1024; // 100MB public void processLargeImage(File largeImage) throws IOException { Runtime runtime = Runtime.getRuntime(); // 检查可用内存 long freeMemory = runtime.maxMemory() - (runtime.totalMemory() - runtime.freeMemory()); if (freeMemory < MAX_MEMORY) { System.gc(); // 建议垃圾回收 freeMemory = runtime.maxMemory() - (runtime.totalMemory() - runtime.freeMemory()); } if (freeMemory < MAX_MEMORY) { // 使用流式处理或分块处理 processInChunks(largeImage); } else { // 可以完整加载到内存 BufferedImage image = ImageIO.read(largeImage); processFullImage(image); } } private void processInChunks(File file) throws IOException { // 实现分块处理逻辑... } }

🔮 未来展望与扩展

TwelveMonkeys ImageIO 项目持续发展,每月发布包含 bug 修复和小功能的更新版本,每季度推出包含重大功能的版本更新。项目路线图包括:

  1. 更多格式支持:持续扩展对新兴图像格式的支持
  2. 性能优化:进一步提升处理速度和内存效率
  3. 云原生适配:优化在容器化环境中的表现
  4. AI 集成:为机器学习应用提供更好的图像预处理支持

图:TwelveMonkeys ImageIO 支持复杂的 CMYK 色彩空间和 ICC 配置文件处理,满足专业印刷需求

结语

TwelveMonkeys ImageIO 为 Java 开发者提供了一个强大而灵活的图像处理解决方案。无论是处理专业设计文件、历史遗留格式,还是需要增强 JDK 内置格式的功能,这个库都能提供出色的支持。其模块化设计、与标准 ImageIO API 的完美兼容性,以及活跃的社区维护,使其成为 Java 图像处理领域的首选工具。

通过本文介绍的最佳实践和高级技巧,你可以充分利用 TwelveMonkeys ImageIO 的强大功能,构建高效、稳定的图像处理应用。记住,成功的图像处理不仅仅是读取和写入文件,更是关于选择正确的工具、优化性能和提供优秀的用户体验。

【免费下载链接】TwelveMonkeysTwelveMonkeys ImageIO: Additional plug-ins and extensions for Java's ImageIO项目地址: https://gitcode.com/gh_mirrors/tw/TwelveMonkeys

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.gsyq.cn/news/1635998.html

相关文章:

  • 在PC上畅玩Switch游戏:Ryujinx模拟器完全指南与实战技巧
  • SWEET32漏洞深度解析:从生日攻击原理到企业TLS/SSL安全加固实战
  • AI Agent 面试题 711:Agent的Prompt注入防御的实时监控和告警
  • 宝塔部署的前后端项目从IP访问改成自定义域名访问
  • Fast-GitHub终极指南:如何让GitHub下载速度提升10倍的免费解决方案
  • STM32F439ZG与171010550的DC-DC降压电源设计实战
  • 终极指南:如何用SuperSQL让AI帮你写SQL,5分钟完成数据库查询革命
  • E-Hentai批量下载解决方案:基于浏览器脚本的高效图片归档创新方法
  • 解锁PS3手柄在Windows上的完全潜力:DsHidMini深度体验指南
  • 逆向工程实战:58同城App密码加密算法解析与Python复现
  • 如何免费获取国家中小学智慧教育平台电子课本PDF:智能解析下载方案
  • E-Hentai漫画批量下载:三分钟搞定完整图库归档的终极方案
  • yolov26改进 | 主干/Backbone篇 | 轻量级移动端网络ShuffleNetV2(附代码+修改教程)
  • 企业微信数据合规管理:WechatBakTool技术架构与商业价值分析
  • 免费终极图表编辑器:Mermaid Live Editor零代码可视化创作指南
  • 如何在浏览器中实现图像隐写?StegOnline:零基础掌握LSB数据隐藏的终极指南
  • 系统架构图绘制——让架构“可视化“
  • 2026,手机自制电子证件照全指南:详细步骤与无水印工具实操教学
  • 个人技术开发者如何为宠物门店做小程序?解决预约、卖货难题
  • 2026最新8款学生免费编程工具平替权威实测合集
  • 2026:智能短视频总结工具选哪个,免费版够用的只留这一个
  • openEuler-pkginfo配置详解:如何定制化你的Gitee操作环境
  • 裂痕深处:弦理论的未竟困局与NKS计算范式的统一之问
  • 【强烈推荐收藏】2026网络安全:国家战略支柱与最确定职业红利
  • 从单体架构到 LTAP:数据库存储革新,实现无限存储与实时数据分析
  • 三步极速上手:E-Hentai漫画批量下载高效解决方案
  • 嵌入式应用开发笔记之web端设备控制台
  • RAG沉寂了吗?一场被误读的退场与一场正在发生的进化
  • 每天10分钟学会OceanBase系列(Day 9):SQL性能诊断,看懂执行计划不再难
  • 汽车功能安全的“独立性“要求:为什么两个系统“都好“不等于“一起好“