dl
dl_file_csv.h
浏览该文件的文档.
1
12#pragma once
13
14#include <string>
15
16#include "dl_file.h"
18#include "dl_type.h"
19#include "base/dl_range_find.h"
20#include "base/dl_vector2.h"
21#include "math/dl_math.h"
24namespace dl::FileCsv
25{
26
27constexpr uint32_t CSV_FILE_TYPE = 316;
28
36bool Read(std::string_view path_name, Vector2<std::string>& ret)
37{
38 assert(!ret.IsEmpty());
39
40 std::ifstream ifs = File::Get(path_name, false);
41 if (!ifs.is_open())
42 {
43 log_err("csv文件加载失败:{}", path_name);
44 return false;
45 }
46
47 // 状态
48 enum class Flag
49 {
50 NORMAL, // 正常
51 LEFT, // 读取到了前引号
52 TWICE, // 再次读到引号
53 }flag;
54 flag = Flag::NORMAL;
55 // 所有
57 // 当前行
58 std::vector<std::string> line;
59 // 当前段
60 std::string temp;
61
62 while (!ifs.eof())
63 {
64 char ch = ifs.get();
65 switch (flag)
66 {
67 case Flag::NORMAL:
68 if (ch == '\"')// 进入引号模式
69 flag = Flag::LEFT;
70 else if (ch == ',')// 写入段
71 {
72 line.push_back(temp);
73 temp.clear();
74 }
75 else if (ch == '\n')// 写入行,还要写入当前段
76 {
77 line.push_back(temp);
78 temp.clear();
79 all.PushBack(line);
80 line.clear();
81 }
82 else
83 temp.push_back(ch);
84 break;
85 case Flag::LEFT:
86 if (ch == '\"')// 进入两次引号模式
87 flag = Flag::TWICE;
88 else if (ch == '\n')// 换行符写入
89 temp.push_back(ch);
90 else
91 temp.push_back(ch);
92 break;
93 case Flag::TWICE:
94 // 这里 必须是引号转义,或是结束(逗号结束,或段结束),其他状态则为错误
95 if (ch == '\"')//写入一个引号
96 {
97 temp.push_back(ch);
98 flag = Flag::LEFT;
99 }
100 else if (ch == ',')// 写入段
101 {
102 line.push_back(temp);
103 temp.clear();
104 flag = Flag::NORMAL;
105 }
106 else if (ch == '\n')// 写入行与段
107 {
108 line.push_back(temp);
109 temp.clear();
110 all.PushBack(line);
111 line.clear();
112 flag = Flag::NORMAL;
113 }
114 else
115 {
116 log_err0("引号转义出现错误的状态!");
117 return false;
118 }
119 break;
120 default:
121 log_err0("错误的状态!");
122 return false;
123 }
124 }
125 ret = std::move(all);
126 return true;
127}
128//
130//* @brief 序列化 逗号分隔文件
131//*/
132//void Serialize(std::string_view path_name, std::string_view out)
133//{
134// Vector2<std::string> mul_str;
135// if (!Read(path_name, mul_str))
136// return;
137//
138// struct TypeFlag
139// {
140// enum
141// {
142// Z8,
143// Z16,
144// Z32,
145// Z64,
146// N8,
147// N16,
148// N32,
149// N64,
150// FLOAT,
151// DOUBLE,
152// STRING,
153// NONE,//占位(=或未知类型)
154// ALIGN,//字节对齐填充
155// }_type;
156// size_t _size;//用于字符串记录长度,包含结束符
157// };
158//
159// //单个元素缓冲区
160// std::byte* p = nullptr;
161// std::size_t line_size = 0;
162//
163// //输出流
164// StreamOutput s;
165//
166// //类型标签
167// std::vector<TypeFlag> vec_flag;
168//
169// //寻找 = 的位置
170// Index2 pos = Find::FirstIndex(mul_str, "=");
171//
172// if (pos[1] == -1)
173// {
174// log_err("=标签查找失败:{}", path_name);
175// return;
176// }
177//
178// //字段行
179// {
180// std::string* vec_str = mul_str[pos[1]];
181//
182// //最大字段长度
183// std::size_t max_size = 1;
184// //统计数据大小
185// for (std::size_t i = pos[0]; i < mul_str.GetWidth(); ++i)
186// {
187// if (vec_str[i] == "uint8_t")
188// {
189// vec_flag.push_back({ TypeFlag::N8, 0 });
190// line_size += sizeof(uint8_t);
191// }
192// else if (vec_str[i] == "uint16_t")
193// {
194// vec_flag.push_back({ TypeFlag::N16, 0 });
195// line_size += sizeof(uint16_t);
196// }
197// else if (vec_str[i] == "uint32_t")
198// {
199// vec_flag.push_back({ TypeFlag::N32, 0 });
200// line_size += sizeof(uint32_t);
201// }
202// else if (vec_str[i] == "int32_t")
203// {
204// vec_flag.push_back({ TypeFlag::Z32, 0 });
205// line_size += sizeof(int32_t);
206// }
207// else if (vec_str[i] == "float")
208// {
209// if (sizeof(float) > max_size)
210// max_size = sizeof(float);
211//
212// std::size_t start = line_size ? Math::Align(line_size, alignof(float)) : 0;
213// if (start != line_size) vec_flag.push_back({ TypeFlag::ALIGN, start - line_size });
214//
215// vec_flag.push_back({ TypeFlag::FLOAT, 0 });
216// line_size += sizeof(float);
217// }
218// else if (vec_str[i] == "double")
219// {
220// if (sizeof(double) > max_size)
221// max_size = sizeof(double);
222//
223// std::size_t start = line_size ? Math::Align(line_size, alignof(double)) : 0;
224// if (start != line_size) vec_flag.push_back({ TypeFlag::ALIGN, start - line_size });
225//
226// vec_flag.push_back({ TypeFlag::DOUBLE, 0 });
227// line_size += sizeof(double);
228// }
229// else
230// {
231// size_t pos = vec_str[i].find("str");
232// if (pos != std::string::npos)
233// {
234// if (sizeof(char) > max_size)
235// max_size = sizeof(char);
236//
237// size_t start = line_size ? Math::Align(line_size, alignof(char)) : 0;
238// if (start != line_size) vec_flag.push_back({ TypeFlag::ALIGN, start - line_size });
239//
240// //
241// size_t str_length = std::stoi(std::string(vec_str[i].begin() + 3, vec_str[i].end()));
242// if (str_length == 0)
243// {
244// log_err("字符串必须指定长度,例如str8:{}", path_name);
245// str_length = 16;//手动设置大小
246// }
247// vec_flag.push_back({ TypeFlag::STRING, str_length });
248// line_size += sizeof(char) * str_length;
249// }
250// else
251// {
252// vec_flag.push_back({ TypeFlag::NONE, 0 });
253// line_size += 0;
254// if (!vec_str[i].empty() && vec_str[i] != "=")
255// log_warn("未知类型标签:{},{}", path_name, vec_str[i]);
256// }
257// }
258// }
259//
260// if (line_size == 0)
261// {
262// log_err("数据大小为0:{}", path_name );
263// return;
264// }
265//
266// //最大元素对齐
267// std::size_t start = line_size ? Math::Align(line_size, max_size) : 0;
268// line_size = start;
269//
270// p = (std::byte*)malloc(line_size);
271//
272//
273// //写入类型
274// uint32_t id = CSV_FILE_TYPE;
275// s.Write(&id);
276//
277// //写入单行大小
278// s.Write64(&line_size);
279// }
280//
281// //统计除了用于对齐的元素个数
282// ptrdiff_t w = pos[0] + count_if(vec_flag.begin(), vec_flag.end(), [](const TypeFlag& flag)
283// {
284// return flag._type != TypeFlag::ALIGN;
285// });
286//
287// //数据行
288// for (size_t h = pos[1] + 1; h < mul_str.GetHeight(); ++h)
289// {
290// std::string* vec_str = mul_str[h];
291//
292// if (vec_str[pos[0]] != "+")
293// {
294// continue;
295// }
296//
297// if (p == nullptr
298// || vec_flag.empty()
299// || line_size == 0)
300// {
301// log_err("类型标签未成功读取:{}", path_name);
302// return;
303// }
304//
305// if (vec_str.size() != w)
306// {
307// std::string str_all;
308// for (auto& iter : vec_str)
309// {
310// str_all += iter;
311// str_all += ",";
312// }
313// log_err("此行元素个数不匹配:{},{}", path_name, str_all);
314// continue;
315// }
316//
317// size_t offset = 0;
318// size_t j = pos[0];//元素下标
319// for (size_t i = 0; i < vec_flag.size(); ++i)
320// {
321// if (vec_flag[i]._type == TypeFlag::ALIGN)
322// {
323// offset += vec_flag[i]._size;
324// continue;
325// }
326//
327//#define DEF_SERIALIZE_CSV_LINE(flag, type, func)\
328//if (vec_flag[i]._type == TypeFlag::flag)\
329//{\
330//type v = 0;\
331//if (!vec_str[j].empty())\
332//{\
333// if(Sub::IsBegin(vec_str[j], std::string("0x")))\
334// v = func(vec_str[j], nullptr, 16);\
335// else\
336// v = func(vec_str[j]);\
337//}\
338//*(type*)(p + offset) = v;\
339//offset += sizeof(type);\
340//++j;\
341//continue;\
342//}
343//
344//#define DEF_SERIALIZE_CSV_LINE_F(flag, type, func)\
345//if (vec_flag[i]._type == TypeFlag::flag)\
346//{\
347//*(type*)(p + offset) = (type)(vec_str[j].empty() ? 0 : func(vec_str[j]));\
348//offset += sizeof(type);\
349//++j;\
350//continue;\
351//}
352// DEF_SERIALIZE_CSV_LINE(Z8, int8_t, stoi);
353// DEF_SERIALIZE_CSV_LINE(Z16, int16_t, stoi);
354// DEF_SERIALIZE_CSV_LINE(Z32, int32_t, stoi);
355// DEF_SERIALIZE_CSV_LINE(Z64, int64_t, stoll);
356// DEF_SERIALIZE_CSV_LINE(N8, uint8_t, stoi);
357// DEF_SERIALIZE_CSV_LINE(N16, uint16_t, stoi);
358// DEF_SERIALIZE_CSV_LINE(N32, uint32_t, stoul);
359// DEF_SERIALIZE_CSV_LINE(N64, uint64_t, stoull);
360// DEF_SERIALIZE_CSV_LINE_F(FLOAT, float, stof);
361// DEF_SERIALIZE_CSV_LINE_F(DOUBLE, double, stod);
362//
363// if (vec_flag[i]._type == TypeFlag::STRING)
364// {//string
365// if (vec_str[j].empty())
366// *(char*)(p + offset) = 0;
367// else//strcpy_s并没有考虑源过大
368// CodeCvt::Utf8::Copy((char*)(p + offset), vec_flag[i]._size, vec_str[j]);
369//
370// //strcpy_s((char*)(p + offset), vec_flag[i]._size, vec_str[j].c_str());
371// offset += sizeof(char) * vec_flag[i]._size;
372// }
373//
374// ++j;
375//
376// }
377//
378// if (line_size != offset)
379// {
380// log_err("单行写入大小不匹配:{}", path_name );
381// }
382//
383// s.Write(p, line_size);
384// }
385// free(p);
386// s.Save(out);
387//}
388
389
393template<typename T, typename F>
394void Deserialize(std::string_view path_name, F fn)
395{
396 StreamInput s;
397 s.LoadFromFile(path_name);
398
399 //id
400 uint32_t id = 0;
401 s.Read(&id);
402 if (id != CSV_FILE_TYPE)
403 {
404 log_err("CSV二进制文件错误:{}", path_name);
405 return;
406 }
407
408 //大小检查
409 std::size_t size = 0;
410 s.Read64(&size);
411 if (size != sizeof(T))
412 {
413 log_err("CSV二进制文件不匹配POD类型大小{},{}:{}", size, sizeof(T), path_name);
414 return;
415 }
416
417
418 while (!s.IsEnd())
419 {
420 T t;
421 s.Read(&t);
422 fn(t);
423 }
424}
425
426template<typename T>
427void Deserialize(std::string_view path_name, std::vector<T>& container)
428{
429 Deserialize<T>(path_name, [&](T& line)
430 {
431 container.push_back(line);
432 });
433}
434
435}
二进制输入流
void Read64(T *data)
写入一个类型,写为64位,用于在64位平台的大小不一致,所以特殊处理
bool LoadFromFile(std::string_view path_name, bool decompress=false, size_t length=0)
从文件读到内存,可选长度
void PushBack(std::vector< T > &vec)
插入行
bool IsEmpty() const
文件系统
#define log_err(...)
数学相关的通用算法
通用类型
2维vector
csv格式解析
bool Read(std::string_view path_name, Vector2< std::string > &ret)
读取一个CSV文件,拆解为每行(换行使用 替代,所有/变为\)
void Deserialize(std::string_view path_name, F fn)
序列化 逗号分隔文件
constexpr uint32_t CSV_FILE_TYPE
std::ifstream Get(std::string_view path_name, bool is_binary=true)
void log_err0(std::string_view str, DL_SOURCE_LOCATION)