You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
5.6 KiB
C++

2 months ago
// io_utils.cpp - 通用 IO 工具实现
#include "io_utils.h"
#include "config.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include <ctime>
#include <algorithm>
#include <cstdio>
// stb single-header JPEG 编码器(实现仅保留在本文件,全工程只定义一次)
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "PAVO2_SDK/include/stb_image_write.h"
#ifdef _WIN32
#include <direct.h> // _mkdir
#include <windows.h>
#include <io.h>
#include <iostream>
#include <cerrno>
#else
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <cerrno>
#endif
std::string trim_str(const std::string& s)
{
size_t b = s.find_first_not_of(" \t\r\n");
if (b == std::string::npos) return "";
size_t e = s.find_last_not_of(" \t\r\n");
return s.substr(b, e - b + 1);
}
std::string gbk_to_utf8(const std::string& s)
{
#ifdef _WIN32
if (s.empty()) return s;
int wlen = MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), nullptr, 0);
if (wlen <= 0) return s;
std::wstring wbuf(wlen, L'\0');
MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), &wbuf[0], wlen);
int ulen = WideCharToMultiByte(CP_UTF8, 0, wbuf.c_str(), wlen, nullptr, 0, nullptr, nullptr);
if (ulen <= 0) return s;
std::string ubuf(ulen, '\0');
WideCharToMultiByte(CP_UTF8, 0, wbuf.c_str(), wlen, &ubuf[0], ulen, nullptr, nullptr);
return ubuf;
#else
return s;
#endif
}
#ifdef _WIN32
static bool mkdir_one(const std::string& path) { return _mkdir(path.c_str()) == 0 || errno == EEXIST; }
#else
static bool mkdir_one(const std::string& path) { return mkdir(path.c_str(), 0777) == 0 || errno == EEXIST; }
#endif
bool make_dirs(const std::string& path)
{
if (path.empty()) return false;
std::string cur;
size_t pos = 0;
while (pos <= path.size()) {
size_t slash = path.find_first_of("/\\", pos);
cur += path.substr(pos, (slash == std::string::npos ? path.size() : slash) - pos);
if (!cur.empty() && cur != ".") {
if (!mkdir_one(cur) && errno != EEXIST) return false;
}
if (slash == std::string::npos) break;
cur += '/';
pos = slash + 1;
}
return true;
}
std::string make_task_dir(const std::string& task_id)
{
std::string base = "data";
make_dirs(base);
time_t rawtime = std::time(nullptr);
struct tm* t = std::localtime(&rawtime);
char date_buf[16], time_buf[16];
std::strftime(date_buf, sizeof(date_buf), "%Y%m%d", t);
std::strftime(time_buf, sizeof(time_buf), "%H%M%S", t);
std::string day_dir = base + "/" + date_buf;
make_dirs(day_dir);
std::string task_dir = day_dir + "/" + time_buf;
if (!task_id.empty()) task_dir += "_" + task_id;
else task_dir += "_";
make_dirs(task_dir);
return task_dir;
}
// 仅 Windows 用简化目录遍历;其他平台留空实现(本程序运行于 Windows)
void clean_expired_log_dirs()
{
if (Log_Retain_Days <= 0) return;
#ifdef _WIN32
std::string base = "data";
WIN32_FIND_DATAA fd;
HANDLE h = FindFirstFileA((base + "/*").c_str(), &fd);
if (h == INVALID_HANDLE_VALUE) return;
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue;
std::string name = fd.cFileName;
if (name.size() != 8) continue; // 仅处理 YYYYMMDD
bool is_num = true;
for (char c : name) if (c < '0' || c > '9') { is_num = false; break; }
if (!is_num) continue;
time_t now = std::time(nullptr);
struct tm* t = std::localtime(&now);
t->tm_year = std::atoi(name.substr(0, 4).c_str()) - 1900;
t->tm_mon = std::atoi(name.substr(4, 2).c_str()) - 1;
t->tm_mday = std::atoi(name.substr(6, 2).c_str());
time_t dir_time = std::mktime(t);
double days = std::difftime(now, dir_time) / 86400.0;
if (days > Log_Retain_Days) {
std::string full = base + "/" + name;
// 删除目录(含子文件,Windows 下逐级删除)
std::string del_cmd = "rmdir /s /q \"" + full + "\"";
system(del_cmd.c_str());
std::cout << "[清理] 已删除过期日志目录: " << full << std::endl;
}
} while (FindNextFileA(h, &fd));
FindClose(h);
#endif
}
void save_pcd_ascii(const std::string& filename,
const std::vector<double>& xs,
const std::vector<double>& ys,
const std::vector<double>& zs)
{
size_t n = xs.size();
std::ostringstream oss;
oss << "# .PCD v0.7 - Point Cloud Data file format\n"
<< "VERSION 0.7\n"
<< "FIELDS x y z\n"
<< "SIZE 4 4 4\n"
<< "TYPE F F F\n"
<< "COUNT 1 1 1\n"
<< "WIDTH " << n << "\n"
<< "HEIGHT 1\n"
<< "VIEWPOINT 0 0 0 1 0 0 0\n"
<< "POINTS " << n << "\n"
<< "DATA ascii\n"
<< std::fixed << std::setprecision(1);
for (size_t i = 0; i < n; i++) {
oss << xs[i] << " " << ys[i] << " " << zs[i] << "\n";
}
std::string buf = oss.str();
std::ofstream f(filename, std::ios::binary);
f.write(buf.data(), (std::streamsize)buf.size());
f.close();
}
bool save_jpg_gray(const std::string& filename, int width, int height,
const std::vector<uint8_t>& pixels, int quality)
{
std::vector<uint8_t> rgb(width * height * 3);
for (int i = 0; i < width * height; i++) {
uint8_t v = pixels[i];
rgb[i * 3 + 0] = v;
rgb[i * 3 + 1] = v;
rgb[i * 3 + 2] = v;
}
int ret = stbi_write_jpg(filename.c_str(), width, height, 3, rgb.data(), quality);
return ret != 0;
}