Java ESC打印是指通过Java程序发送ESC/POS指令控制打印机(如热敏小票机)进行文档输出的技术,ESC/POS是 Epson 公司制定的针式打印机指令集,支持文本、条码、二维码、图片等打印格式,Java 实现时,通常通过 Socket 通信将指令集发送至打印机,或使用第三方库(如 ESC/POS for Java、JavaPOS)简化开发,核心流程包括初始化打印机、构建指令(如设置字体、对齐、走纸等)、发送数据并处理打印状态,该技术广泛应用于零售、餐饮、物流等场景,具有高效、标准化、跨设备兼容等优势,是 Java 开发中实现小票、标签打印的常用方案。
Java实现ESC指令打印:从原理到实践
在票据打印、标签打印、小票打印等商业应用场景中,打印机通常通过特定的控制指令来实现文本格式化、切纸、条码打印等功能,ESC(Escape)指令集是一种广泛应用于热敏打印机、针式打印机的控制协议,通过发送特定的ASCII码序列,可以精确控制打印机的输出行为,本文将详细介绍ESC指令的工作原理,并重点讲解如何在Java中实现ESC指令打印,包括核心代码、常见指令用法及实践技巧。
ESC指令基础:打印机的"控制语言"
ESC指令是一种以"ESC字符(ASCII码27,十六进制0x1B)"开头的控制指令序列,用于向打印机发送格式化、功能控制等命令。ESC E表示加粗,ESC d表示切纸,GS k表示打印条码等,不同品牌和型号的打印机(如佳博、得实、斑马、星等)对ESC指令的支持略有差异,但核心指令集(如ESC/POS标准)基本通用。
常用ESC指令示例(ESC/POS标准):
| 指令功能 | ASCII序列(十六进制) | 说明 |
|---|---|---|
| 初始化打印机 | 1B 40 | 清空缓冲区,恢复默认设置 |
| 选择加粗模式 | 1B 45 01 | 01:开启加粗,00:关闭加粗 |
| 设置对齐方式 | 1B 61 00(左)/01(中)/02(右) | 设置文本对齐 |
| 打印并换行 | 0A | 换行符(LF) |
| 切纸 | 1B 56 00 | 切纸(部分打印机需要GS V) |
| 打印条码 | 1D 6B 00(条码类型)+数据 | 以UPC-A为例,需指定条码类型和内容 |
| 设置行间距 | 1B 33 n | 设置行间距(n为十六进制值) |
| 设置字符大小 | 1D 21 n | n=00:正常,n=10:宽体,n=20:高体 |
Java实现ESC打印的核心技术
在Java中实现ESC打印,本质是通过IO流向打印机发送二进制指令序列,核心步骤包括:获取打印机连接、构造ESC指令、发送指令数据。
打印机连接方式
打印机连接方式主要有本地连接(如LPT端口、USB虚拟端口)和网络连接(TCP/IP),Java中需根据连接方式选择不同的IO流:
- 本地打印机:通过
java.io.FileOutputStream写入打印机端口(如LPT1、USB001,Windows系统下可通过"设备和打印机"查看端口名称)。 - 网络打印机:通过
java.net.Socket连接打印机的IP和端口(如9100,常见网络打印机端口)。 - 蓝牙打印机:通过Java蓝牙API连接(需要额外权限和库支持)。
构造ESC指令
ESC指令本质是二进制数据流,需将指令转换为字节数组发送,加粗指令ESC E 01转换为字节数组为:{0x1B, 0x45, 0x01},Java中可通过以下方式构造:
// 方式1:直接构造字节数组
byte[] boldOn = {0x1B, 0x45, 0x01};
// 方式2:使用ByteArrayOutputStream动态拼接
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(0x1B); // ESC
baos.write(0x45); // E
baos.write(0x01); // 开启加粗
byte[] command = baos.toByteArray();
发送指令数据
通过IO流的write()方法将字节数组写入打印机,确保数据完整发送(需处理IO异常和流关闭),建议使用try-with-resources确保资源释放。
Java实现ESC打印:代码示例
示例1:本地打印机打印小票(包含格式化文本和切纸)
import java.io.FileOutputStream;
import java.io.IOException;
public class LocalEscPrint {
public static void main(String[] args) {
// Windows系统下打印机端口(需根据实际环境修改)
String printerPort = "LPT1";
// 或USB虚拟端口(如"USB001")
// String printerPort = "\\\\?\\USB001";
try (FileOutputStream fos = new FileOutputStream(printerPort)) {
// 1. 初始化打印机
fos.write(new byte[]{0x1B, 0x40}); // ESC @
// 2. 设置对齐方式(居中)
fos.write(new byte[]{0x1B, 0x61, 0x01}); // ESC a 01
// 3. 打印店铺名称(加粗)
fos.write(new byte[]{0x1B, 0x45, 0x01}); // ESC E 01(开启加粗)
fos.write("欢迎光临XXX商店".getBytes("GBK"));
fos.write(new byte[]{0x0A}); // 换行
// 4. 关闭加粗
fos.write(new byte[]{0x1B, 0x45, 0x00}); // ESC E 00(关闭加粗)
// 5. 打印商品列表(左对齐)
fos.write(new byte[]{0x1B, 0x61, 0x00}); // ESC a 00(左对齐)
fos.write("商品1 x2 ¥10.00".getBytes("GBK"));
fos.write(new byte[]{0x0A});
fos.write("商品2 x1 ¥25.50".getBytes("GBK"));
fos.write(new byte[]{0x0A});
// 6. 打印横线
fos.write("--------------------------------".getBytes("GBK"));
fos.write(new byte[]{0x0A});
// 7. 打印总计(右对齐)
fos.write(new byte[]{0x1B, 0x61, 0x02}); // ESC a 02(右对齐)
fos.write("总计: ¥45.50".getBytes("GBK"));
fos.write(new byte[]{0x0A});
// 8. 切纸
fos.write(new byte[]{0x1B, 0x56, 0x00}); // ESC V 00(切纸)
System.out.println("打印指令发送成功!");
} catch (IOException e) {
System.err.println("打印失败: " + e.getMessage());
e.printStackTrace();
}
}
}
示例2:网络打印机打印条码(TCP/IP连接)
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
public class NetworkEscPrint {
public static void main(String[] args) {
String printerIp = "192.168.1.100"; // 打印机IP
int printerPort = 9100; // 网络打印机默认端口
try (Socket socket = new Socket();
OutputStream os = socket.getOutputStream()) {
// 连接打印机(设置5秒超时)
socket.connect(new InetSocketAddress(printerIp, printerPort), 5000);
// 1. 初始化打印机
os.write(new byte[]{0x1B, 0x40});
// 2. 设置条码类型(CODE128)
os.write(new byte[]{0x1D, 0x6B, 0x49}); // GS k I (CODE128)
// 3. 打印条码内容
String barcodeData = "123456789012";
os.write(barcodeData.getBytes("GBK"));
// 4. 打印条码下方文本
os.write(new byte[]{0x0A}); // 换行
os.write("商品条码".getBytes("GBK"));
// 5. 切纸
os.write(new byte[]{0x1B, 0x56, 0x00});
System.out.println("