C#提取文件時(shí)間戳實(shí)現(xiàn)實(shí)現(xiàn)與性能優(yōu)化
在汽車(chē)電子和工業(yè)控制領(lǐng)域,CAN總線(xiàn)是最常用的通信協(xié)議之一。而ASC(ASCII)文件作為CAN總線(xiàn)數(shù)據(jù)的標(biāo)準(zhǔn)日志格式,廣泛應(yīng)用于數(shù)據(jù)記錄和分析場(chǎng)景。本文將深入探討如何高效地從CAN ASC文件中提取時(shí)間戳數(shù)據(jù),并分享一個(gè)高性能的C#實(shí)現(xiàn)方案。
一、CAN ASC文件格式解析
CAN ASC文件是一種基于文本的日志格式,通常包含CAN總線(xiàn)的通信時(shí)間戳、消息ID、數(shù)據(jù)長(zhǎng)度和數(shù)據(jù)內(nèi)容。一個(gè)典型的ASC文件片段如下:
date Tue Aug 22 15:35:42 2023
base hex timestamps absolute
0.000000 18F00000x Rx d 8 00 00 00 00 00 00 00 00 Channel=1
0.001000 18F00001x Rx d 8 00 00 00 00 00 00 00 00 Channel=1
0.002000 18F00002x Rx d 8 00 00 00 00 00 00 00 00 Channel=1
其中,每行的第一個(gè)字段(如0.000000)即為時(shí)間戳,表示消息發(fā)送的相對(duì)或絕對(duì)時(shí)間。在解析時(shí),我們需要跳過(guò)文件頭的元數(shù)據(jù)行,從第三行開(kāi)始提取時(shí)間戳信息。
二、時(shí)間戳提取的C#實(shí)現(xiàn)
下面是一個(gè)高效的C#實(shí)現(xiàn),用于從ASC文件中提取時(shí)間戳數(shù)據(jù):
public class AscExtractor
{
public List<decimal> Extract(string path)
{
var text = "";
using (var sr = new StreamReader(path))
{
text = sr.ReadToEnd();
}
var options = StringSplitOptions.RemoveEmptyEntries;
return text.Split(new char[] { '\n', '\r' }, options)
.Where(t => !string.IsNullOrWhiteSpace(t))
.Skip(2)
.Select(t => t.Split(new char[] { ' ', '\t' }, options))
.Select(t => t[0])
.Select(t => decimal.Parse(t))
.ToList();
}
}
代碼解析:
- 文件讀?。菏褂肧treamReader一次性讀取整個(gè)文件內(nèi)容,適用于中等大小的ASC文件。
- 行分割:通過(guò)Split方法將文本按行分割,并移除空行。
- 跳過(guò)頭部:使用Skip(2)跳過(guò)文件的前兩行元數(shù)據(jù),可根據(jù)實(shí)際情況調(diào)整。
- 字段提?。簩?duì)每行數(shù)據(jù)按空格或制表符分割,提取第一個(gè)字段作為時(shí)間戳。
- 類(lèi)型轉(zhuǎn)換:將字符串類(lèi)型的時(shí)間戳解析為decimal類(lèi)型,確保高精度。
三、性能優(yōu)化與最佳實(shí)踐
1. 大文件處理優(yōu)化
對(duì)于GB級(jí)別的超大ASC文件,一次性讀取整個(gè)文件會(huì)導(dǎo)致內(nèi)存溢出。可采用流式處理方式:
public List<decimal> ExtractLargeFile(string path)
{
var timestamps = new List<decimal>();
using (var sr = new StreamReader(path))
{
// 跳過(guò)頭部
sr.ReadLine();
sr.ReadLine();
var line = "";
while ((line = sr.ReadLine()) != null)
{
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
var fields = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (fields.Length > 0)
{
timestamps.Add(decimal.Parse(fields[0]));
}
}
}
return timestamps;
}
2. 異常處理增強(qiáng)
在實(shí)際應(yīng)用中,ASC文件可能包含格式錯(cuò)誤的行,需要添加異常處理:
public List<decimal> ExtractWithErrorHandling(string path)
{
var timestamps = new List<decimal>();
using (var sr = new StreamReader(path))
{
// 跳過(guò)頭部
sr.ReadLine();
sr.ReadLine();
var line = "";
var lineNumber = 3; // 從第三行開(kāi)始計(jì)數(shù)
while ((line = sr.ReadLine()) != null)
{
try
{
if (string.IsNullOrWhiteSpace(line)) continue;
var fields = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (fields.Length > 0)
{
timestamps.Add(decimal.Parse(fields[0]));
}
}
catch (Exception ex)
{
// 記錄錯(cuò)誤行號(hào)和錯(cuò)誤信息
Console.WriteLine($"Error parsing line {lineNumber}: {ex.Message}");
}
lineNumber++;
}
}
return timestamps;
}
3. 并行處理加速
對(duì)于多核CPU系統(tǒng),可使用PLINQ并行處理提高解析速度:
public List<decimal> ExtractParallel(string path)
{
string text;
using (var sr = new StreamReader(path))
{
text = sr.ReadToEnd();
}
return text.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
.AsParallel()
.AsOrdered()
.Where(line => !string.IsNullOrWhiteSpace(line))
.Skip(2)
.Select(line =>
{
var fields = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
return decimal.Parse(fields[0]);
})
.ToList();
}
四、應(yīng)用場(chǎng)景與擴(kuò)展
1. 時(shí)間序列分析
提取的時(shí)間戳可用于分析CAN消息的發(fā)送頻率、間隔分布等時(shí)序特征,幫助診斷總線(xiàn)負(fù)載和通信異常。
2. 數(shù)據(jù)可視化
結(jié)合圖表庫(kù)(如OxyPlot、Chart.js),將時(shí)間戳與CAN消息內(nèi)容結(jié)合,直觀(guān)展示總線(xiàn)通信狀態(tài):
3. 高性能擴(kuò)展
對(duì)于工業(yè)級(jí)應(yīng)用,可考慮使用MemoryMappedFile進(jìn)行內(nèi)存映射讀取,或使用Span<T>進(jìn)行零分配解析,進(jìn)一步提升性能。
五、總結(jié)
本文介紹了CAN ASC文件的格式特點(diǎn),并提供了多種C#實(shí)現(xiàn)方案來(lái)提取時(shí)間戳數(shù)據(jù)。在實(shí)際應(yīng)用中,應(yīng)根據(jù)文件大小、性能需求和容錯(cuò)要求選擇合適的實(shí)現(xiàn)方式。對(duì)于中小文件,可使用簡(jiǎn)潔的LINQ鏈?zhǔn)教幚?;?duì)于大文件,則建議采用流式處理或并行解析。通過(guò)合理優(yōu)化,可實(shí)現(xiàn)每秒百萬(wàn)級(jí)時(shí)間戳的高效提取,滿(mǎn)足大多數(shù)工業(yè)和汽車(chē)電子領(lǐng)域的數(shù)據(jù)分析需求。
到此這篇關(guān)于C#提取文件時(shí)間戳實(shí)現(xiàn)實(shí)現(xiàn)與性能優(yōu)化的文章就介紹到這了,更多相關(guān)C#提取文件時(shí)間戳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于WPF開(kāi)發(fā)一個(gè)分頁(yè)控件
這篇文章主要為大家詳細(xì)介紹了如何使用WPF(Windows?Presentation?Foundation)開(kāi)發(fā)一個(gè)分頁(yè)控件,并深入解析其實(shí)現(xiàn)原理,感興趣的小伙伴可以了解下2024-04-04
C#操作LINQ to SQL組件進(jìn)行數(shù)據(jù)庫(kù)建模的基本教程
這篇文章主要介紹了C#操作LINQ to SQL組件進(jìn)行數(shù)據(jù)庫(kù)建模的基本教程,LINQ to SQL被集成在.NET框架之中,需要的朋友可以參考下2016-03-03
asp.net頁(yè)面中如何獲取Excel表的內(nèi)容
在瀏覽網(wǎng)頁(yè)時(shí),一定會(huì)看到我們需要保存的信息,我們比較常用的方法就是拖動(dòng)鼠標(biāo),選中我們需要的內(nèi)容,然后ctrl+c,然后在保持到excel當(dāng)中去,那么如何用asp.net獲取excel表的內(nèi)容呢,下面小編就給大家介紹asp.net獲取excel表的內(nèi)容,需要的朋友可以參考下2015-08-08
C#判斷一個(gè)類(lèi)是否實(shí)現(xiàn)了某個(gè)接口3種實(shí)現(xiàn)方法
這篇文章主要介紹了C#判斷一個(gè)類(lèi)是否實(shí)現(xiàn)了某個(gè)接口3種實(shí)現(xiàn)方法,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06
C#實(shí)現(xiàn)對(duì)象的序列化和反序列化
這篇文章介紹了C#實(shí)現(xiàn)對(duì)象序列化和反序列化的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07

