如何用Java向GSM Modem发送AT+CMGR/AT+CMGL指令读取并打印短信?
用Java结合RXTX实现短信读取与删除
我完全理解作为新手在接触RXTX、Java串口通信和AT指令时的迷茫——你已经成功搞定了串口检测,这已经是非常好的开端了!接下来我就一步步给你实现读取收到的短信、打印内容并删除的Java代码,同时解释每个部分的作用,帮你理清逻辑。
先明确核心AT指令的作用
咱们先把要用到的关键AT指令搞清楚:
AT+CMGL="ALL":列出所有短信(包括已读、未读),返回每条短信的索引、状态、发送方号码、时间和内容AT+CMGR=<索引>:读取指定索引的单条短信(如果只是批量读取,用CMGL更高效)AT+CMGD=<索引>:删除指定索引的短信
完整实现代码
下面的代码是在你现有串口检测代码的基础上扩展的,包含了串口打开、AT指令发送、短信解析和删除的完整逻辑:
package anothersms; import gnu.io.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.Enumeration; public class SMSReader { private SerialPort serialPort; private OutputStream outputStream; private BufferedReader inputReader; // 串口参数配置(要和你的短信模块参数一致,常见是9600波特率) private static final int BAUD_RATE = 9600; private static final int DATA_BITS = SerialPort.DATABITS_8; private static final int STOP_BITS = SerialPort.STOPBITS_1; private static final int PARITY = SerialPort.PARITY_NONE; public static void main(String[] args) { SMSReader smsReader = new SMSReader(); // 先检测可用串口,你可以选择要连接的串口名称,比如"COM3" String targetPort = smsReader.detectAvailablePorts(); if (targetPort == null) { System.out.println("未找到可用串口!"); return; } System.out.println("尝试连接串口:" + targetPort); // 打开串口并初始化 if (smsReader.openSerialPort(targetPort)) { // 初始化短信模块(发送AT指令确认连接) if (smsReader.sendATCommand("AT") != null) { System.out.println("模块连接成功!"); // 读取并处理所有短信 smsReader.readAndProcessSMS(); } else { System.out.println("模块连接失败!"); } // 关闭串口 smsReader.closeSerialPort(); } else { System.out.println("串口打开失败!"); } } // 检测可用串口(复用你原来的代码) private String detectAvailablePorts() { System.out.println("正在检测可用串口..."); CommPortIdentifier serialPortId; Enumeration enumComm = CommPortIdentifier.getPortIdentifiers(); String firstPort = null; while (enumComm.hasMoreElements()) { serialPortId = (CommPortIdentifier) enumComm.nextElement(); if (serialPortId.getPortType() == CommPortIdentifier.PORT_SERIAL) { System.out.println("找到串口:" + serialPortId.getName()); if (firstPort == null) { firstPort = serialPortId.getName(); } } } return firstPort; } // 打开指定串口 private boolean openSerialPort(String portName) { try { CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); // 打开串口,超时时间2000ms CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000); if (commPort instanceof SerialPort) { serialPort = (SerialPort) commPort; // 设置串口参数 serialPort.setSerialPortParams(BAUD_RATE, DATA_BITS, STOP_BITS, PARITY); // 获取输入输出流 outputStream = serialPort.getOutputStream(); inputReader = new BufferedReader(new InputStreamReader(serialPort.getInputStream())); return true; } else { System.out.println("指定端口不是串口!"); } } catch (NoSuchPortException | PortInUseException | UnsupportedCommOperationException | IOException e) { e.printStackTrace(); } return false; } // 发送AT指令并返回响应 private String sendATCommand(String command) { try { // 发送指令,注意要加\r\n结尾(AT指令的标准结束符) outputStream.write((command + "\r\n").getBytes()); outputStream.flush(); // 读取响应,这里简单读取所有返回内容 StringBuilder response = new StringBuilder(); Thread.sleep(1000); // 等待模块响应,根据实际情况调整时间 while (inputReader.ready()) { response.append(inputReader.readLine()).append("\n"); } return response.toString(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } return null; } // 读取所有短信并处理(打印+删除) private void readAndProcessSMS() { // 发送读取所有短信的指令 String smsResponse = sendATCommand("AT+CMGL=\"ALL\""); if (smsResponse == null || !smsResponse.contains("OK")) { System.out.println("读取短信失败!"); return; } System.out.println("\n=== 读取到的短信内容 ==="); // 解析短信响应,拆分每条短信 String[] smsLines = smsResponse.split("\n"); for (int i = 0; i < smsLines.length; i++) { String line = smsLines[i].trim(); // 短信索引行格式:+CMGL: <索引>,<状态>,<号码>,"",<时间> if (line.startsWith("+CMGL:")) { // 提取索引 String[] parts = line.split(","); int smsIndex = Integer.parseInt(parts[0].split(":")[1].trim()); String senderNumber = parts[2].replace("\"", ""); String smsTime = parts[4].replace("\"", ""); // 下一行是短信内容 String smsContent = smsLines[i + 1].trim(); // 打印短信信息 System.out.println("短信索引:" + smsIndex); System.out.println("发送方:" + senderNumber); System.out.println("时间:" + smsTime); System.out.println("内容:" + smsContent); System.out.println("------------------------"); // 删除这条短信 String deleteResponse = sendATCommand("AT+CMGD=" + smsIndex); if (deleteResponse != null && deleteResponse.contains("OK")) { System.out.println("索引" + smsIndex + "的短信已删除"); } else { System.out.println("索引" + smsIndex + "的短信删除失败"); } } } } // 关闭串口资源 private void closeSerialPort() { try { if (inputReader != null) { inputReader.close(); } if (outputStream != null) { outputStream.close(); } if (serialPort != null) { serialPort.close(); } } catch (IOException e) { e.printStackTrace(); } } }
关键细节说明
- 串口参数匹配:代码里的波特率、数据位等参数必须和你的短信模块一致,大部分模块默认是9600波特率,如果不对可以调整
BAUD_RATE的值。 - AT指令结束符:所有AT指令必须以
\r\n结尾,这是串口通信的标准要求,不然模块可能不响应。 - 响应等待时间:发送指令后要给模块一点处理时间,代码里用
Thread.sleep(1000),如果你的模块响应慢,可以适当延长时间。 - 短信解析逻辑:
AT+CMGL的响应格式是固定的,我们通过识别+CMGL:开头的行来提取短信索引、号码等信息,下一行就是短信内容,这个解析逻辑可以根据你的模块返回的格式微调。
注意事项
- 确保你已经正确配置了RXTX的DLL文件(32位/64位要和JVM匹配),不然代码会抛出找不到库的异常。
- 测试时要确保短信模块已经正确连接到电脑串口,并且模块处于正常工作状态(可以用串口助手先发送AT指令测试模块是否响应)。
内容的提问来源于stack exchange,提问作者ikiSiTamvaaan
相关产品推荐
相关产品推荐

