|
|
|
|
@ -0,0 +1,154 @@
|
|
|
|
|
#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;
|
|
|
|
|
};
|