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.

154 lines
3.7 KiB
C

#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <vector>
#include <thread>
#include <cctype>
#include <cstdint>
#include <utility>
// Windows 内存映射文件封装类
class CMappedFile
{
public:
explicit CMappedFile(const char* path)
{
m_hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
if (m_hFile == INVALID_HANDLE_VALUE)
return;
m_hMapping = CreateFileMappingA(m_hFile, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (!m_hMapping)
{
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
return;
}
m_data = static_cast<const char*>(MapViewOfFile(m_hMapping, FILE_MAP_READ, 0, 0, 0));
}
~CMappedFile()
{
if (m_data) UnmapViewOfFile(m_data);
if (m_hMapping) CloseHandle(m_hMapping);
if (m_hFile != INVALID_HANDLE_VALUE) CloseHandle(m_hFile);
}
bool IsValid() const { return m_data != nullptr; }
const char* Data() const { return m_data; }
size_t Size() const
{
LARGE_INTEGER li{};
li.LowPart = GetFileSize(m_hFile, reinterpret_cast<DWORD*>(&li.HighPart));
return li.QuadPart;
}
private:
HANDLE m_hFile = INVALID_HANDLE_VALUE;
HANDLE m_hMapping = nullptr;
const char* m_data = nullptr;
};
//光斑RawData多线程解析
class BeamCsvParserMT
{
public:
unsigned char* Load(const char* path, int& width, int& height)
{
m_file = std::make_unique<CMappedFile>(path);
if (!m_file->IsValid())
{
width = height = 0;
return nullptr;
}
size_t cols = DetectColumnCount(m_file->Data());
m_threadResults.resize(1);
m_threadResults[0].reserve(cols*cols);
ParseBlock(0, m_file->Size(), m_threadResults[0]);
size_t total = 0;
for (auto& v : m_threadResults)
total += v.size();
unsigned char* result = new unsigned char[total];
unsigned char* dst = result;
for (auto& v : m_threadResults)
{
memcpy(dst, v.data(), v.size());
dst += v.size();
}
height = static_cast<int>(total / cols);
width = static_cast<int>(cols);
return result;
}
private:
// ===============================
// 内部工具函数
// ===============================
size_t DetectColumnCount(const char* data) const
{
size_t cols = 1;
for (const char* p = data; *p != '\n' && *p != '\r' && *p != '\0'; ++p)
{
if (*p == ',') ++cols;
}
return cols;
}
std::vector<std::pair<size_t, size_t>>SplitIntoLineBlocks(const char* data, size_t size, size_t threadCount, size_t & Rows) const
{
std::vector<size_t> offsets{ 0 };//声明并放入一个0值
for (size_t i = 0; i < size; ++i)
{
if (data[i] == '\n')
offsets.emplace_back(i + 1);
}
if (offsets.back() < size)
offsets.emplace_back(size);
Rows = offsets.size() - 1;
size_t linesPerThread = Rows / threadCount;
std::vector<std::pair<size_t, size_t>> blocks;
for (size_t t = 0; t < threadCount; ++t)
{
size_t start = offsets[t * linesPerThread];
size_t end = (t == threadCount - 1) ? offsets.back() : offsets[(t + 1) * linesPerThread];
blocks.emplace_back(start, end);
}
return blocks;
}
void ParseBlock(size_t start, size_t end, std::vector<unsigned char>& out) const
{
const char* p = m_file->Data() + start;
const char* blockEnd = m_file->Data() + end;
const char* fieldStart = p;
char sVal[32]{ 0 };
while (p < blockEnd)
{
if (*p == ',' || *p == '\n' || *p == '\r')
{
memset(sVal, 0, 32);
memcpy(sVal, fieldStart, p - fieldStart);
out.emplace_back(static_cast<unsigned char>(min(atoi(sVal), 254)));
if (*p == '\r' && (p + 1 < blockEnd && *(p + 1) == '\n'))
++p;
fieldStart = p + 1;
}
++p;
}
}
private:
std::unique_ptr<CMappedFile> m_file;
std::vector<std::vector<unsigned char>> m_threadResults;
};