这些天在做的一个项目里面,客户对于自动化要求比较高,我们使用的大华的工业相机和配套的OCR软件,来拍照识别入库的货物的sku码和sn码,并发送给WCS系统,我们WCS系统再发给WMS系统。
刚开始,我们制定的方案是OCR——》输送线PLC——》WCS——》WMS,但是PLC那边说由于一个区域有8个相机一起给他发数据无法存储那么多数据,后来就改为OCR直接通过TCP通信发给WCS这边。OCR是客户端发送,WCS是服务端接收。由于种种硬件软件问题导致拖延项目交付时间,我这边就写一个程序直接从他们存在用户电脑上的日志文件获取我们需要的数据并发给我们WCS服务端,做为最后万不得已下的兜底,不过幸好最后没有用上。
言归正传,实现此功能需要分三步:①读取本地日志文件中更新的内容。②从更新的内容中获取我们需要的格式数据。③以客户端形式发送数据给WCS系统。
一:读取本地日志文件中更新的内容首先得先确定要读取的日志:
我们WCS每个服务的日志都会存在指定的日志文件夹下,日志名称也会以当天的日期来命名,这样便比较好找,如下:
//获取本地指定日志文件
public static void getLogByDate(){
//日志文件存放路径
String local = "D:\logs\rgv";
//获取当前年月日用来查找对应日期的日志
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateNowStr = sdf.format(date);
String fileName = "info_"+dateNowStr+".log";
String fileUrl = local+"\"+fileName;
System.out.println("日志文件路径:"+fileUrl);
}
当然,像大华那种一直在拍照识别,他们对日志做了设置,即每隔日志最大只能有20M,因此当天就会存在很多个日志文件,我们需要做的就是获取到最新修改的日志,如下:
//获取指定目录下最新修改的文件
public static void getLastLog(){
//日志文件存放路径
String local = "D:\\logs\\rgv";
List list = getFileSort(local);
if (list.size()==0){
System.out.println("该目录下无文件!");
}
System.out.println("目录下每个文件按时间排序: ");
for (File file : list) {
System.out.print(file.getName() +"; ");
}
System.out.println("");
//最新的文件含日志文件和控制台启动文件日志,并且控制台启动文件日志在最前面
System.out.println("最新更新的日志文件名:"+list.get(1).getName());
}
//获取目录下所有文件(按时间排序)
public static List getFileSort(String path) {
List list = getFiles(path, new ArrayList());
if (list != null && list.size() > 0) {
Collections.sort(list, new Comparator() {
public int compare(File file, File newFile) {
if (file.lastModified() < newFile.lastModified()) {
return 1;
} else if (file.lastModified() == newFile.lastModified()) {
return 0;
} else {
return -1;
}
}
});
}
return list;
}
//获取目录下所有文件
public static List getFiles(String realpath, List files) {
File realFile = new File(realpath);
if (realFile.isDirectory()) {
File[] subfiles = realFile.listFiles();
for (File file : subfiles) {
if (file.isDirectory()) {
getFiles(file.getAbsolutePath(), files);
} else {
files.add(file);
}
}
}
return files;
}
确定完读取的日志文件,那么便需要读取该文件内的所有的内容:
对于一个本地文件来说,我们可以逐行读取数据然后放到一个String字符串里面来构建该文件内所有内容,如下:
//逐行读取文件内容
public static void readFileByLine() {
String fileUrl = "D:\logs\rgv\info_2022-04-02.log";
File file = new File(fileUrl);
if (!file.exists()){
System.out.println("无此文件!");
return ;
}
BufferedReader reader = null;
StringBuffer sbf = new StringBuffer();
try {
reader = new BufferedReader(new FileReader(file));
String lineStr = null;
//逐行读取文件内容并塞到一起
while ((lineStr = reader.readLine()) != null) {
sbf.append(lineStr);
}
String result = sbf.toString();
System.out.println("逐行读取文件内容结果为:");
System.out.println(result);
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
但是如上使用readLine方法逐行读取数据需要反复读取文件,影响效率,在条件允许的情况下,我们可以按字节流方式先将文件都读入内存,再一次性进行编码转换,如下:
//一次性读取文件内所有内容
public static void readFile() {
String fileUrl = "D:\logs\rgv\info_2022-04-02.log";
String encoding = "UTF-8";
File file = new File(fileUrl);
if (!file.exists()){
System.out.println("无此文件!");
return ;
}
Long filelength = file.length();
byte[] filecontent = new byte[filelength.intValue()];
FileInputStream in = null;
try {
in = new FileInputStream(file);
in.read(filecontent);
String result = new String(filecontent, encoding);
System.out.println("一次性读取文件所有内容:");
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
读取完后,将新的日志内容内老的日志内容部分去除,剩下的就是更新的部分了。
二、从更新的内容中获取我们需要的格式数据大华日志格式数据简略示例: logger.info("Send bytes: 23-36-39-31-33-33-35-36-32-30-30-33-36-36-2C");
从更新的日志内容根据“Send bytes: ”开头,换行符结尾来遍历更新的的内容中的条码数据,再进行转换将十六进制数据转为ASCII码,当然由于OCR一直在拍照识别,会存在重复的条码数据,这个时候你可以在发送前进行去重 *** 作再发送,也可以直接发送,让服务端进行去重 *** 作。
三、将实时获取的条码数据以客户端形式发送数据给WCS系统这边我就使用之前我对接扫码q写的一个SocketDemo来发送数据,如下:
package com.example.tcp.netty.socket.client.demo;
import com.example.tcp.netty.socket.client.barcode.HexToASCToBytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class SocketDemo {
private static Socket socket;
private static final int SOCKET_TIME_OUT = 3000;
private Logger logger = LoggerFactory.getLogger(SocketDemo.class);
// 获得的扫描的结果
String barcode = null;
private String ip;
private int port;
public SocketDemo(String ip, int port) {
this.ip = ip;
this.port = port;
}
/**
* 连接服务端的实现。
*/
private void connect() {
try {
logger.info("begin connect to server {}:{}", ip, port);
// 通过IP与端口号建立socket连接
socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), SOCKET_TIME_OUT);
if (!socket.isConnected()) {
logger.error("fail to connect to server {}:{}", ip, port);
}
logger.info("success connect to server {}:{}", ip, port);
} catch (IOException e) {
logger.error("fail to connect to server {} ", ip);
barcode = null;
}
}
public void reConnect() {
Socket closeSocket = socket;
try {
// 防止异常,不论如何最后都要关闭socket连接,否则下次无法再次创建
if (closeSocket!=null){
closeSocket.close();
}
connect();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
public void write(String data) {
try {
if (socket == null) {
connect();
}
// 连接未成功
if (null == socket || !socket.isConnected() || socket.isClosed()) {
socket = null;
return;
}
OutputStream os = socket.getOutputStream();
byte[] sendBytes = data.getBytes(StandardCharsets.UTF_8);
os.write(sendBytes);
logger.info("success send data to WCS :{}",data);
os.close();
} catch (IOException e) {
Socket closeSocket = socket;
socket = null;
try {
// 防止异常,不论如何最后都要关闭socket连接,否则下次无法再次创建
closeSocket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
public void read() {
try {
if (socket == null) {
connect();
}
// 连接未成功
if (null == socket || !socket.isConnected() || socket.isClosed()) {
socket = null;
return;
}
OutputStream os = socket.getOutputStream();
// 读取扫码q获取到的数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
byte[] bytes = new byte[1]; // 一次读取一个byte
String barcode = null;
String ret = "";
while (dis.read(bytes) != -1) {
//byte数组转十六进制字符串
ret += HexToASCToBytes.ByteArrayToHexString(bytes) + " ";
if (dis.available() == 0) {
// 去除前面的状态符,“30 30 30 20 ”
ret = ret.substring(12);
// 将转换的十六进制字符串再转为ASC码
String[] hexs = ret.split(" ");
for (String str : hexs) {
barcode += HexToASCToBytes.convertHexToASC(str);
}
}
}
logger.info("barcode get pallet code :" + barcode);
// 对应的进行赋值。
this.barcode = barcode;
os.close();
bis.close();
dis.close();
} catch (IOException e) {
Socket closeSocket = socket;
socket = null;
logger.error("fail to read barcode ", e);
// 当前的设置为空。
barcode = null;
try {
// 防止异常,不论如何最后都要关闭socket连接,否则下次无法再次创建
closeSocket.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
}
获取本地文件日志并发送指定格式数据FileControl:
package com.example.tcp.file;
import com.example.tcp.netty.socket.client.demo.SocketDemo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author zhangqianwei
* @date 2021/4/2 9:30
*/
@Component
@Configuration
public class FileControl {
private Logger logger = LoggerFactory.getLogger(FileControl.class);
//本地日志存放路径
private String local = "D:\\logs\\rgv";
//日志实时更新的数据
private String info = null;
//用于存放上一个日志文件内容字符串长度以此来截取更新部分
private int size = 0;
private String ip = "192.168.2.172";
private int port = 20000;
//用于计数,当>3000次即5分钟无编码数据即断开重连
private int count = 0;
SocketDemo socketDemo;
@PostConstruct
public void load() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
//连接WCS服务端
socketDemo = new SocketDemo(ip, port);
if (count>3000){
//多次没有数据输出,重连,清空次数
socketDemo.reConnect();
count = 0;
}
//获取当前年月日用来查找对应日期的日志
String fileUrl = getLogByDate();
//获取当天的日志所有内容
String nowStr = readFile(fileUrl);
info = nowStr.substring(size);
size = nowStr.length();
//筛选更新的日志指定格式内容
handelInfo();
Thread.sleep(100);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
t.setName("file_control");
t.start();
}
//获取本地指定日志文件
public String getLogByDate(){
//获取当前年月日用来查找对应日期的日志
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateNowStr = sdf.format(date);
String fileName = "info_"+dateNowStr+".log";
String fileUrl = local+"\\"+fileName;
return fileUrl;
}
public String readFile(String fileUrl) throws IOException {
String encoding = "UTF-8";
File file = new File(fileUrl);
if (!file.exists()){
logger.info("无此文件!");
return null;
}
Long filelength = file.length();
byte[] filecontent = new byte[filelength.intValue()];
FileInputStream in = null;
try {
in = new FileInputStream(file);
in.read(filecontent);
return new String(filecontent, encoding);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
in.close();
}
}
public void handelInfo(){
String request = info;
int startIndex = 0;
int endIndex = 0;
String startStr = "Send bytes: ";
String endStr = "\r\n";
if (!request.contains(startStr)){
count = count+1;
}
//处理接收到的数据,如果为空或者不包含startStr开头数据则不处理
while(!request.equals("") && request.contains(startStr)){
startIndex = request.indexOf(startStr);
//防止出现tcp分包现象,确保每一个数据都是startStr开头,endStr结尾
if (startIndex==-1){
continue;
}
//+12是为了去除startStr的长度
request = request.substring(startIndex+12);
endIndex = request.indexOf(endStr);
if (endIndex==-1){
continue;
}
String ocrHexStr = request.substring(0,endIndex);
//23表示#开头,2C表示, 即我们规定的#开头,结尾
ocrHexStr = ocrHexStr.replace("-","");
logger.info("OCR获取的十六进制货物编码::{}",ocrHexStr);
String asc = "";
//十六进制转ASCII码
asc = convertHexToASC(ocrHexStr);
//SKU码或者SN码
logger.info("OCR获取的编码数据:{}",asc);
//将获取到的货物编码以UTF-8形式转换byte数组发送给WCS服务端
socketDemo.write(asc);
logger.info("发送成功");
request = request.substring(endIndex + 1);
}
}
//16进制字符串转ASCII码
public String convertHexToASC(String hex){
StringBuilder sb = new StringBuilder();
StringBuilder temp = new StringBuilder();
for( int i=0; i
日志文件的一些 *** 作示例LogDemo:
package com.example.tcp.file;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author zhangqianwei
* @date 2021/4/7 15:24
*/
public class LogDemo {
public static void main(String[] args) {
getLogByDate();
getLastLog();
readFileByLine();
readFile();
}
//获取本地指定日志文件
public static void getLogByDate(){
//日志文件存放路径
String local = "D:\\logs\\rgv";
//获取当前年月日用来查找对应日期的日志
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateNowStr = sdf.format(date);
String fileName = "info_"+dateNowStr+".log";
String fileUrl = local+"\\"+fileName;
System.out.println("日志文件路径:"+fileUrl);
}
//获取指定目录下最新修改的文件
public static void getLastLog(){
//日志文件存放路径
String local = "D:\\logs\\rgv";
List list = getFileSort(local);
if (list.size()==0){
System.out.println("该目录下无文件!");
}
System.out.println("目录下每个文件按时间排序: ");
for (File file : list) {
System.out.print(file.getName() +"; ");
}
System.out.println("");
//最新的文件含日志文件和控制台启动文件日志,并且控制台启动文件日志在最前面
System.out.println("最新更新的日志文件名:"+list.get(1).getName());
}
//获取目录下所有文件(按时间排序)
public static List getFileSort(String path) {
List list = getFiles(path, new ArrayList());
if (list != null && list.size() > 0) {
Collections.sort(list, new Comparator() {
public int compare(File file, File newFile) {
if (file.lastModified() < newFile.lastModified()) {
return 1;
} else if (file.lastModified() == newFile.lastModified()) {
return 0;
} else {
return -1;
}
}
});
}
return list;
}
//获取目录下所有文件
public static List getFiles(String realpath, List files) {
File realFile = new File(realpath);
if (realFile.isDirectory()) {
File[] subfiles = realFile.listFiles();
for (File file : subfiles) {
if (file.isDirectory()) {
getFiles(file.getAbsolutePath(), files);
} else {
files.add(file);
}
}
}
return files;
}
//逐行读取文件内容
public static void readFileByLine() {
String fileUrl = "D:\\logs\\rgv\\info_2022-04-02.log";
File file = new File(fileUrl);
if (!file.exists()){
System.out.println("无此文件!");
return ;
}
BufferedReader reader = null;
StringBuffer sbf = new StringBuffer();
try {
reader = new BufferedReader(new FileReader(file));
String lineStr = null;
//逐行读取文件内容并塞到一起
while ((lineStr = reader.readLine()) != null) {
sbf.append(lineStr);
}
String result = sbf.toString();
System.out.println("逐行读取文件内容结果为:");
System.out.println(result);
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
//一次性读取文件内所有内容
public static void readFile() {
String fileUrl = "D:\\logs\\rgv\\info_2022-04-02.log";
String encoding = "UTF-8";
File file = new File(fileUrl);
if (!file.exists()){
System.out.println("无此文件!");
return ;
}
Long filelength = file.length();
byte[] filecontent = new byte[filelength.intValue()];
FileInputStream in = null;
try {
in = new FileInputStream(file);
in.read(filecontent);
String result = new String(filecontent, encoding);
System.out.println("一次性读取文件所有内容:");
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
日志存放路径,日志格式:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)