|
|
|
|
@ -21,6 +21,7 @@
|
|
|
|
|
#include <thread>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include "snowflake.hpp"
|
|
|
|
|
|
|
|
|
|
int _sysmkdir_2(const std::string &dir)
|
|
|
|
|
@ -69,8 +70,10 @@ std::string CheckUtil::getCurrentDate()
|
|
|
|
|
// 将 tv_sec 转换为 time_t 类型,代表自1970年1月1日起的秒数
|
|
|
|
|
time_t raw_time = tv.tv_sec;
|
|
|
|
|
|
|
|
|
|
// 使用 localtime 将 time_t 转换为 tm 结构体
|
|
|
|
|
struct tm *time_info = localtime(&raw_time);
|
|
|
|
|
// 使用 localtime_r 转换为 tm 结构体。
|
|
|
|
|
// 注意:localtime() 返回共享的静态缓冲区,多线程并发调用会互相覆盖(tm 内容串数据)。
|
|
|
|
|
struct tm time_buf;
|
|
|
|
|
struct tm *time_info = localtime_r(&raw_time, &time_buf);
|
|
|
|
|
|
|
|
|
|
// 使用字符串流格式化为 "YYYY-MM-DD"
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
@ -80,13 +83,34 @@ std::string CheckUtil::getCurrentDate()
|
|
|
|
|
|
|
|
|
|
return oss.str(); // 返回日期字符串
|
|
|
|
|
}
|
|
|
|
|
std::string CheckUtil::getCurrentDateYMD()
|
|
|
|
|
{
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
|
|
|
|
|
|
time_t raw_time = tv.tv_sec;
|
|
|
|
|
// localtime_r 为线程安全版本
|
|
|
|
|
struct tm time_buf;
|
|
|
|
|
struct tm *time_info = localtime_r(&raw_time, &time_buf);
|
|
|
|
|
|
|
|
|
|
// 固定 8 位 "YYYYMMDD", 便于文件名检索与排序
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << std::setfill('0')
|
|
|
|
|
<< std::setw(4) << (time_info->tm_year + 1900)
|
|
|
|
|
<< std::setw(2) << (time_info->tm_mon + 1)
|
|
|
|
|
<< std::setw(2) << time_info->tm_mday;
|
|
|
|
|
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
std::string CheckUtil::getCurTimeHMS()
|
|
|
|
|
{
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
gettimeofday(&tv, NULL); // 获取当前时间
|
|
|
|
|
|
|
|
|
|
time_t raw_time = tv.tv_sec;
|
|
|
|
|
struct tm *time_info = localtime(&raw_time);
|
|
|
|
|
// 使用 localtime_r(线程安全);localtime() 的静态缓冲会被其它线程并发覆盖
|
|
|
|
|
struct tm time_buf;
|
|
|
|
|
struct tm *time_info = localtime_r(&raw_time, &time_buf);
|
|
|
|
|
|
|
|
|
|
int millisec = tv.tv_usec / 1000; // 微秒转毫秒
|
|
|
|
|
|
|
|
|
|
@ -120,6 +144,40 @@ int64_t CheckUtil::getSnowId()
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CheckUtil::GetUniqueImgPath(const std::string &strDir, const std::string &strPrefix, const std::string &strName, const std::string &strExt)
|
|
|
|
|
{
|
|
|
|
|
if (strDir.empty())
|
|
|
|
|
{
|
|
|
|
|
return strDir + strPrefix + strName + strExt;
|
|
|
|
|
}
|
|
|
|
|
// 目录不存在时 O_CREAT 会失败, 先建目录(已存在时内部无副作用)
|
|
|
|
|
CreateDir(strDir);
|
|
|
|
|
|
|
|
|
|
// 去重序号插在前缀之后: <年月日>[_序号]_<通道>_<用途>.png
|
|
|
|
|
// 同一产品的每个 strName 每轮只会写一次, 所以各文件序号天然同步:
|
|
|
|
|
// 第 1 轮 -> <年月日>_<名称>.png、第 2 轮 -> <年月日>_1_<名称>.png、第 3 轮 -> <年月日>_2_<名称>.png ...
|
|
|
|
|
const std::string strHead = strPrefix.empty() ? std::string("") : (strPrefix + "_");
|
|
|
|
|
for (int i = 0; i < 100000; i++)
|
|
|
|
|
{
|
|
|
|
|
std::string strPath = strDir + strHead + (i == 0 ? std::string("") : std::to_string(i) + "_") + strName + strExt;
|
|
|
|
|
// O_EXCL: 文件不存在才能创建成功, 即是"原子占位", 并发安全
|
|
|
|
|
int fd = ::open(strPath.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0644);
|
|
|
|
|
if (fd >= 0)
|
|
|
|
|
{
|
|
|
|
|
::close(fd);
|
|
|
|
|
return strPath;
|
|
|
|
|
}
|
|
|
|
|
if (errno != EEXIST)
|
|
|
|
|
{
|
|
|
|
|
// 非"已存在"类错误(权限/路径等)不再重试, 直接返回让 imwrite 把错误暴露出来
|
|
|
|
|
printf("create img file[%s] error: %d %s\n", strPath.c_str(), errno, strerror(errno));
|
|
|
|
|
return strPath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 序号用尽的兜底(实际不会发生)
|
|
|
|
|
return strDir + strHead + std::to_string(CheckUtil::getcurTime()) + "_" + strName + strExt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CheckUtil::JudgRect(cv::Rect roi, int img_w, int img_h)
|
|
|
|
|
{
|
|
|
|
|
if (img_w <= 0 || img_h <= 0)
|
|
|
|
|
|