登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

Java PrintService 怎样确认打印机接受的文档类型

来源:17golang原创

时间:2026-10-30 16:57:49 114浏览 收藏

Java 打印不是先把文件交给任意打印机,再等待失败结果。更稳妥的做法是先拿到一个 PrintService,查询它接受的 DocFlavor,再把具体纸张、份数等属性放进同一个请求上下文判断。

确认打印机接受的文档类型,先调用 getSupportedDocFlavors() 看能力集合,或用 isDocFlavorSupported(flavor) 判断一个格式;如果还带有纸张等属性,则继续调用 getUnsupportedAttributes(flavor, attributes) 检查组合,而不能只看格式支持。

Java 官方文档地址:https://docs.oracle.com/en/java/javase/25/docs/api/java.desktop/javax/print/PrintService.html

先分清三种判断

PrintService 描述的是打印服务的能力。文档类型由 DocFlavor 表示,它同时包含 MIME 类型和数据表示类,例如输入流、字节数组或字符流。打印服务提供三层判断:

要回答的问题适合的 API结果含义
这个服务大致接受哪些文档表示getSupportedDocFlavors()返回 DocFlavor 数组
某一个格式能不能提交isDocFlavorSupported(flavor)返回 true 或 false
格式和纸张等属性能否一起提交getUnsupportedAttributes(flavor, attrs)null 表示没有发现不支持属性
PrintService 的文档格式能力查询、单项判断和组合判断关系
结构说明图:三种查询分别回答能力集合、单个格式和格式属性组合问题。

这三种调用不是重复的。能力集合适合做打印服务选择或诊断,单项判断适合挡住一个确定的输入格式,组合判断则适合提交前确认本次请求的全部上下文。

列出打印服务接受的文档格式

下面的示例从系统打印服务中选出一个名称包含关键字的服务,然后打印其支持的文档格式。示例只负责表达 API 的使用关系,不把输出描述成本机已经连接的打印机结果。

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import java.util.Arrays;

public final class PrintFlavorCatalog {
    public static void main(String[] args) {
        // 不传 flavor 表示先枚举可见的打印服务,而不是提前限定文档格式。
        PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
        for (PrintService service : services) {
            System.out.println("服务:" + service.getName());

            // 返回值描述该服务可接受的文档表示类型。
            DocFlavor[] flavors = service.getSupportedDocFlavors();
            Arrays.stream(flavors)
                    .map(DocFlavor::toString)
                    .sorted()
                    .forEach(flavor -> System.out.println("  " + flavor));
        }
    }
}

getSupportedDocFlavors() 返回的是数组,数组中的每项都由 MIME 类型和表示类共同定义。相同的 MIME 类型,如果表示类不同,也可能是不同的 DocFlavor。因此不要只截取字符串中的 MIME 部分作为唯一键。

如果程序已经知道目标格式,直接用单项判断更清楚。例如打印 PostScript 输入流时,可以先做如下判断:

import javax.print.DocFlavor;
import javax.print.PrintService;

public final class PrintFlavorCheck {
    public static boolean acceptsPostScript(PrintService service) {
        // 这里的表示类是 InputStream,不能与同 MIME 的其他表示类混为一谈。
        DocFlavor flavor = DocFlavor.INPUT_STREAM.POSTSCRIPT;
        return service != null && service.isDocFlavorSupported(flavor);
    }
}

这个判断只说明格式本身被服务接受。官方文档特别提醒,某个格式不一定和所有打印属性都兼容,所以不要把 true 直接当成“本次打印请求一定可以提交”。

检查格式和打印属性的组合

纸张、方向、份数等属性属于另一个维度。假设我们要提交一个 PostScript 输入流,并要求使用 A4 纸,可以把它们放到 PrintRequestAttributeSet 中,再交给组合检查。

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaSizeName;

public final class PrintRequestCompatibility {
    public static boolean acceptsA4PostScript(PrintService service) {
        // 先固定这次请求真实使用的数据表示类型。
        DocFlavor flavor = DocFlavor.INPUT_STREAM.POSTSCRIPT;
        if (service == null || !service.isDocFlavorSupported(flavor)) {
            // 格式不支持时,不再把属性组合交给后续 API。
            return false;
        }

        PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
        // 属性集合表达本次打印请求,而不是服务的全部默认能力。
        attributes.add(MediaSizeName.ISO_A4);

        // null 表示当前格式与属性组合没有返回不支持项。
        return service.getUnsupportedAttributes(flavor, attributes) == null;
    }
}
DocFlavor 与 PrintRequestAttributeSet 的组合兼容性判断
结构说明图:先确认文档格式,再判断纸张等属性与该格式组合后的兼容性。

getUnsupportedAttributes() 返回非 null 时,返回集合中的属性就是该请求上下文中不支持的部分。它不会替你把请求改成可提交版本;程序可以记录原因、换格式、换属性,或换一个打印服务。

把检查顺序固定在提交前

在真正创建 DocPrintJob 前,可以把策略固定成三步:先确认服务对象存在,再确认 DocFlavor,最后确认属性组合。这样每一步的失败都能给出不同提示,避免把“格式不支持”和“格式支持但 A4 组合不支持”混成同一条异常。

import javax.print.DocFlavor;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.attribute.PrintRequestAttributeSet;

public final class PrintPreflight {
    public static void requireSupported(PrintService service,
                                         DocFlavor flavor,
                                         PrintRequestAttributeSet attributes)
            throws PrintException {
        // 先把调用方错误转换成有含义的失败,不让 null 进入 PrintService。
        if (service == null || flavor == null) {
            throw new PrintException("打印服务和文档格式不能为空");
        }
        if (!service.isDocFlavorSupported(flavor)) {
            throw new PrintException("打印服务不接受文档格式:" + flavor);
        }

        // 属性集合可为 null,表示本次没有额外的请求属性。
        var unsupported = service.getUnsupportedAttributes(flavor, attributes);
        if (unsupported != null) {
            throw new PrintException("打印属性组合不受支持:" + unsupported);
        }
    }
}

这里没有用 getSupportedDocFlavors() 做线性遍历,是因为业务已经知道一个候选格式,单项 API 更能表达意图。需要展示能力列表时再枚举数组;需要提交一个确定请求时,用组合检查作为最后一道边界。

几个容易误判的返回值

  • getSupportedDocFlavors() 至少应描述一个支持的格式,但不要假设数组顺序代表优先级。
  • isDocFlavorSupported(null) 会触发空值错误,调用方应先保证格式对象存在。
  • getUnsupportedAttributes() 返回 null 表示没有发现不支持属性;非 null 才表示返回集合包含不支持项。
  • 如果传入的 DocFlavor 本身不被支持,组合检查可能抛出 IllegalArgumentException,所以顺序不能反过来。
  • 支持格式并不代表打印机已经在线、纸盒有纸或最终作业一定物理完成;本文只覆盖 API 暴露的请求能力判断。

为什么只看 MIME 类型不够?

DocFlavor 同时包含 MIME 类型和数据表示类。输入流、字节数组等表示方式不同,打印服务可以只支持其中一种,所以应直接比较完整的 DocFlavor。

什么时候需要列出全部格式?

当用户要在多个候选格式中选择,或后台要诊断某个打印服务的能力时,使用 getSupportedDocFlavors()。如果格式已经由文件类型确定,优先使用 isDocFlavorSupported()。

属性检查能代替真实打印测试吗?

不能。它只判断打印服务是否接受给定的格式和属性组合,不承诺驱动、网络、纸张供应或设备状态。提交后仍应使用应用自己的作业状态与错误处理。

记住这条顺序即可:先选定 PrintService,再确认完整的 DocFlavor,最后用同一份属性集合检查组合。这样打印格式选择和打印任务提交之间的边界就清楚了。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>