如何使用 Java 将原始数据发送到打印机

How to send raw data to printer with Java

我正在尝试创建一个简单的程序,将字符串发送到打印机进行打印。这是我的程序的样子:

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;

public class PrinterTest {
  public static void main (String [] args) throws PrintException {
    DocPrintJob job = null;
    PrintService[] printServices = 
    PrintServiceLookup.lookupPrintServices(null, null);
    System.out.println("Number of print services: " + printServices.length);
    for (PrintService printer : printServices) {
        System.out.println("Printer: " + printer.getName());
        if (printer.getName().contains("ZM400")) {
            String hello = "Hello";
            DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
            Doc doc = new SimpleDoc(hello, flavor, null);
            job = printer.createPrintJob();
            job.print(doc, null);
        }
    }
  }
}

我将其导出为 jar 文件并 运行 在命令行 (Windows) 上使用:

java -jar PrinterTest.jar

程序 运行s,并开始循环遍历计算机上所有已安装的打印机。但是当它到达我正在寻找的打印机时,我收到以下错误:

Exception in thread "main" sun.print.PrintJobFlavorException: invalid flavor
  at sun.print.Win32PrintJob.print(Unknown Source)
  at PrinterTest.main(PrinterTest.java:21)

不太确定我在这里做错了什么,因为我正在搜索的打印机确实出现了。

-使用以下link供参考:http://docs.oracle.com/javase/7/docs/technotes/guides/jps/spec/jpsOverview.fm4.html

-尝试将 DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN 更改为 DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE,但出现错误 IllegalArgumentException: data is not of declared type

-尝试将 Doc doc = new SimpleDoc(hello, flavor, null) 更改为 Doc doc = new SimpleDoc(hello, null, null),但似乎您需要在那里添加风味。

- 尝试更换打印机,因为我尝试调用的原始打印机是标签打印机,但这并没有什么不同。

知道我做错了什么吗?我该怎么做才能修复此代码并使其打印出来?

更新

我得到了这个(有点)工作。这是我目前所拥有的:

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;

public class PrinterTest {
  public static void main (String [] args) throws PrintException, IOException {
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
    System.out.print("Enter the name of the printer: ");
    String printerName = bufferedReader.readLine();
    System.out.print("Enter a short message of what you would like to print here: ");
    String printerMessage = "PRINTER MESSAGE: " + bufferedReader.readLine();
    boolean printerCheck = false;
    DocPrintJob job = null;
    PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
    System.out.println("Number of print services: " + printServices.length);
    for (PrintService printer : printServices) {
        System.out.println("Printer: " + printer.getName());
        if (printer.getName().contains(printerName)) {
            InputStream inputStream = new ByteArrayInputStream(printerMessage.getBytes());
            DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
            Doc doc = new SimpleDoc(inputStream, flavor, null);
            job = printer.createPrintJob();
            job.print(doc, null);
            printerCheck = true;
        }
    }
    if (printerCheck == false) {
        System.out.println("The printer you were searching for could not be found.");
    }
  }
}

我所做的是将字符串放入输入流,并将 DocFlavor.STRING.TEXT_PLAIN 更改为 DocFlavor.INPUT_STREAM.AUTOSENSE

我现在唯一的小问题是 实际上 什么也不会打印,除非 其他东西 被发送到打印机。暂时留在这里供参考。

异常消息很有帮助,应该可以帮助您找到解决方案。

1)首先,您的打印机不支持这种风格:

 DocFlavor.STRING.TEXT_PLAIN;

这个例外说明了:

Exception in thread "main" sun.print.PrintJobFlavorException: invalid flavor

如果你查看这个常量值的源代码,你会发现它被声明为:

public static final STRING TEXT_PLAIN =
    new STRING ("text/plain; charset=utf-16");

因此,您应该做的第一件事是检查您的打印机支持哪些口味。
要渲染它,更改实际代码:

if (printer.getName().contains("ZM400")) {
    String hello = "Hello";
    DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
    Doc doc = new SimpleDoc(hello, flavor, null);
    job = printer.createPrintJob();
    job.print(doc, null);
}

来自:

if (printer.getName().contains("ZM400")) {
    Arrays.stream(printer.getSupportedDocFlavors()).forEach(f->System.out.println(f.getMediaType() + ":" + f.getMimeType() + ":" + f.getRepresentationClassName()));
    String hello = "Hello";
    DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
    Doc doc = new SimpleDoc(hello, flavor, null);
    job = printer.createPrintJob();
    job.print(doc, null);
}

使用我的打印机,它产生以下输出:

image:image/gif:[B image:image/gif:java.io.InputStream

image:image/gif:java.net.URL image:image/jpeg:[B

image:image/jpeg:java.io.InputStream image:image/jpeg:java.net.URL

image:image/png:[B image:image/png:java.io.InputStream

image:image/png:java.net.URL

application:application/x-java-jvm-local-objectref:java.awt.print.Pageable

application:application/x-java-jvm-local-objectref:java.awt.print.Printable

application:application/octet-stream:[B

application:application/octet-stream:java.net.URL

application:application/octet-stream:java.io.InputStream

您可能会注意到我的打印机不支持 "text/plain; charset=utf-16" 味道也一样。

2) 通过将 flavor 更改为 DocFlavor.INPUT_STREAM.AUTOSENSE,您不会再遇到与缺少 DocFlavor.
支持相关的异常 所以这意味着您的打印机支持DocFlavor.INPUT_STREAM.AUTOSENSE
但是您遇到了另一个问题,因为要打印的数据与关联到 DocFlavor.INPUT_STREAM.AUTOSENSE 的声明类型不匹配:

IllegalArgumentException: data is not of declared type.

DocFlavor中,INPUT_STREAM.AUTOSENSE常量是这样声明的:

    public static final INPUT_STREAM AUTOSENSE =
        new INPUT_STREAM ("application/octet-stream");

这对应于先前输出中最后支持的风格:

application:application/octet-stream:java.io.InputStream

问题就在那里:

String hello = "Hello";     
...
Doc doc = new SimpleDoc(hello, flavor, null);

你没有通过 InputStream 但是 String.

例如,您可以这样提供 InputStream

String hello = "Hello";     
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc doc = new SimpleDoc(new ByteArrayInputStream(hello.getBytes()),
                         flavor, null);

或者你也可以使用这种口味:

application:application/octet-stream:[B

因为您输入的不是 InputStream 而是 String :

这里是要使用的风味常量:

DocFlavor.BYTE_ARRAY.AUTOSENSE

你也可以这样使用:

String hello = "Hello";     
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
Doc doc = new SimpleDoc(hello.getBytes(), flavor, null);