【问题标题】:Finding if printer is online and ready to print查找打印机是否在线并准备好打印
【发布时间】:2017-01-21 03:10:40
【问题描述】:

以下 4 个问题没有帮助,因此这不是重复的:

ONETWOTHREEFOUR


我需要找到一种方法来发现我的系统报告的打印机是否可以打印。

打印机页面:

在图片中,打印机“THERMAL”可以打印,但“HPRT PPTII-A(USB)”不能打印。系统向我显示,通过将不可用的打印机设置为阴影

使用以下代码,我可以找到系统中的所有打印机

public static List<String> getAvailablePrinters() {
    DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
    PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();

    PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, aset);
    ArrayList<String> names = new ArrayList<String>();
    for (PrintService p : services) {
        Attribute at = p.getAttribute(PrinterIsAcceptingJobs.class);
        if (at == PrinterIsAcceptingJobs.ACCEPTING_JOBS) {
            names.add(p.getName());
        }

    }
    return names;
}

输出:

[HPRT PPTII-A(USB), THERMAL]

问题是:这段代码显示了系统曾经安装过的所有打印机。

我需要什么:这个列表应该只包含真正可用的打印机来打印。在这个例子中,它应该只显示“THERMAL”,而不显示“HPRT PPTII-A(USB)”

如何做到这一点?

【问题讨论】:

  • this 呢?
  • 这没什么用,只是把我送到一个文档页面,我不知道该怎么做......添加为一个已检查的问题

标签: java printing printers


【解决方案1】:

如果解决方案是特定于 Windows 的,请尝试WMI4Java。这是我的情况:

如您所见,我的默认打印机“Kyocera Mita FS-1010”处于非活动状态(灰显),因为我只是将其关闭。

现在将其添加到您的 Maven POM:

<dependency>
  <groupId>com.profesorfalken</groupId>
  <artifactId>WMI4Java</artifactId>
  <version>1.4.2</version>
</dependency>

然后就这么简单地列出所有打印机及其各自的状态:

package de.scrum_master.app;

import com.profesorfalken.wmi4java.WMI4Java;
import com.profesorfalken.wmi4java.WMIClass;

import java.util.Arrays;

public class Printer {
    public static void main(String[] args) {
        System.out.println(
            WMI4Java
                .get()
                .properties(Arrays.asList("Name", "WorkOffline"))
                .getRawWMIObjectOutput(WMIClass.WIN32_PRINTER)
        );
    }
}

控制台日志如下:

Name        : WEB.DE Club SmartFax
WorkOffline : False

Name        : Send To OneNote 2016
WorkOffline : False

Name        : Microsoft XPS Document Writer
WorkOffline : False

Name        : Microsoft Print to PDF
WorkOffline : False

Name        : Kyocera Mita FS-1010 KX
WorkOffline : True

Name        : FreePDF
WorkOffline : False

Name        : FinePrint
WorkOffline : False

Name        : Fax
WorkOffline : False

请注意WorkOffline 是京瓷打印机的True。可能这就是你想知道的。

现在稍作修改,以过滤打印机列表,以便仅显示活动打印机:

            WMI4Java
                .get()
                .properties(Arrays.asList("Name", "WorkOffline"))
                .filters(Arrays.asList("$_.WorkOffline -eq 0"))
                .getRawWMIObjectOutput(WMIClass.WIN32_PRINTER)

更新:有人问我如何获取活动打印机名称的列表。好吧,由于我刚刚提交了一个拉取请求的shortcoming in WMI4Java,这并不容易。它使我们解析和过滤原始 WMI 输出,但代码仍然非常简单:

package de.scrum_master.app;

import com.profesorfalken.wmi4java.WMI4Java;
import com.profesorfalken.wmi4java.WMIClass;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Printer {
    public static void main(String[] args) {
        String rawOutput = WMI4Java
            .get()
            .properties(Arrays.asList("Name", "WorkOffline"))
            .filters(Arrays.asList("$_.WorkOffline -eq 0"))
            .getRawWMIObjectOutput(WMIClass.WIN32_PRINTER);
        List<String> printers = Arrays.stream(rawOutput.split("(\r?\n)"))
            .filter(line -> line.startsWith("Name"))
            .map(line -> line.replaceFirst(".* : ", ""))
            .sorted()
            .collect(Collectors.toList());
        System.out.println(printers);
    }
}

控制台输出如下所示:

[Fax, FinePrint, FreePDF, Microsoft Print to PDF, Microsoft XPS Document Writer, Send To OneNote 2016, WEB.DE Club SmartFax]

【讨论】:

  • 以及如何获取活动打印机名称列表?
  • 完美。赏金是你的。不幸的是,这是一个仅限 Windows 的解决方案。解决了我的问题(可能是操作,因为他在 Windows 中询问),但对于未来的用户可能还不够
【解决方案2】:

更新: 我建议不要像这样直接使用 Powershell,而不是查询 WMI“win32_printer”对象,它的 API 更简洁:

Get-Printer | where PrinterStatus -like 'Normal' | fl

查看所有打印机和状态:

Get-Printer | fl Name, PrinterStatus

查看所有属性:

Get-Printer | fl

您仍然可以在 Java 中使用 ProcessBuilder,如下所述。

更新前:

Windows解决方案,查询WMI“win32_printer”对象:

public static void main(String[] args) {
    // select printer that have state = 0 and status = 3, which indicates that printer can print
    ProcessBuilder builder = new ProcessBuilder("powershell.exe", "get-wmiobject -class win32_printer | Select-Object Name, PrinterState, PrinterStatus | where {$_.PrinterState -eq 0 -And $_.PrinterStatus -eq 3}");
    String fullStatus = null;
    Process reg;
    builder.redirectErrorStream(true);
    try {
        reg = builder.start();
        fullStatus = getStringFromInputStream(reg.getInputStream());
        reg.destroy();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    System.out.print(fullStatus);
}

将 InputStream 转换为 String 看这里:comprehensive StackOverflow answer,或者你可以简单地使用:

public static String getStringFromInputStream(InputStream is) {
    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
    try {
        while ((length = is.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    String finalResult = "";
    try {
        finalResult = result.toString("UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return finalResult;
}

输出:

Name                          PrinterState PrinterStatus
----                          ------------ -------------
Foxit Reader PDF Printer                 0             3
Send to OneNote 2010                     0             3
Microsoft XPS Document Writer            0             3
Microsoft Print to PDF                   0             3
Fax                                      0             3
\\192.168.50.192\POS_PRINTER             0             3

如您所见,您现在在字符串中拥有了所有处于工作状态的打印机。

您可以使用现有方法 (getAvailablePrinters()),例如添加如下内容:

    ArrayList<String> workingPrinter = new ArrayList<String>();
    System.out.println("Working printers:");
    for(String printer : getAvailablePrinters()){
        if(fullStatus.contains("\n" + printer + " ")){  // add a newline character before the printer name and space after so that it catches exact name 
            workingPrinter.add(printer);
            System.out.println(printer);
        }
    }

现在您将获得一份不错的工作打印机列表。

控制台输出:

Working printers:
Send to OneNote 2010
Foxit Reader PDF Printer
Microsoft XPS Document Writer
Microsoft Print to PDF
Fax
\\192.168.50.192\POS_PRINTER

当然,您必须小心使用这种方法的名称 - 例如如果“POS_PRINTER”在所有打印机中但不在工作打印机列表中,它仍然可以添加到工作打印机列表中,如果有一个名为“POS_PRINTER 1”的工作打印机,因为该名称包含“\nPOS_PRINTER”字符串...

【讨论】:

  • 谢谢你,这对我帮助很大。我添加了 |格式列表到 powershell 脚本,因为某些打印机名称被切断
  • 没问题,很高兴它帮助了你。你用过这样的东西,我假设:get-wmiobject -class win32_printer | Where-Object {$_.PrinterState -eq 0 -And $_.PrinterStatus -eq 3} | Format-List Name
猜你喜欢
  • 2013-09-10
  • 1970-01-01
  • 2010-12-10
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多