[英]C# - Read bytes from file from a specific string
我正在尝试用 C# 解析crg 文件。 该文件与纯文本和二进制数据混合。 文件的第一部分包含纯文本,而文件的其余部分是二进制文件(大量浮点数),这是一个示例:
$
$ROAD_CRG
reference_line_start_u = 100
reference_line_end_u = 120
$
$KD_DEFINITION
#:KRBI
U:reference line u,m,730.000,0.010
D:reference line phi,rad
D:long section 1,m
D:long section 2,m
D:long section 3,m
...
$
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
�@z����RA����\�l
...
我知道我可以从特定偏移量开始读取字节,但如何找出从哪个字节开始? 二进制部分之前的最后一行将始终包含至少四个美元符号“$$$$”。 这是我到目前为止所得到的:
using var fs = new FileStream(@"crg_sample.crg", FileMode.Open, FileAccess.Read);
var startByte = ??; // How to find out where to start?
using (BinaryReader reader = new BinaryReader(fs))
{
reader.BaseStream.Seek(startByte, SeekOrigin.Begin);
var f = reader.ReadSingle();
Debug.WriteLine(f);
}
当您有文本数据和二进制数据的混合时,您需要将所有内容都视为二进制数据。 这意味着您应该使用原始Stream
访问或类似的东西,并使用二进制 API 来查看文本数据(通常在字节处查找 cr/lf/crlf 作为标记,尽管在您的情况下听起来您可以只查找$$$$
使用二进制 API,然后在之前解码整个块,并向前扫描)。 当您认为有一整行时,您可以使用Encoding
来解析每一行 - 最方便的 API 是encoding.GetString().
当你完成翻翻文本数据作为二进制文件,那么你可以继续解析二进制数据,再次使用二进制API。 我通常也会在这里建议不要使用BinaryReader
,因为坦率地说,它不会比更直接的 API 获得多少好处。 您可能要考虑的另一个问题是 CPU 字节序,但假设这不是问题: BitConverter.ToSingle()
可能是您的朋友。
如果数据大小适中,您可能会发现对数据使用byte[]
最容易; 要么通过File.ReadAllBytes
,要么通过从数组池中租用一个超大的byte[]
,然后从FileStream
加载它。 Stream
API 在这种情况下很尴尬,因为一旦您查看了数据:它已经消失了 - 因此您需要维护自己的后台缓冲区。 在处理大数据时,管道API 非常适合于此,但它是一个高级主题。
更新:此代码可能无法按预期工作。 请查看评论中的宝贵信息。
using (var fs = new FileStream(@"crg_sample.crg", FileMode.Open, FileAccess.Read))
{
using (StreamReader sr = new StreamReader(fs, Encoding.ASCII, true, 1, true))
{
var line = sr.ReadLine();
while (!string.IsNullOrWhiteSpace(line) && !line.Contains("$$$$"))
{
line = sr.ReadLine();
}
}
using (BinaryReader reader = new BinaryReader(fs))
{
// TODO: Start reading the binary data
}
}
解决方案
我知道这远不是最优化的解决方案,但在我的情况下,它成功了,而且由于已知文件的纯文本部分相当小,因此不会导致任何明显的性能问题。 这是代码:
using var fileStream = new FileStream(@"crg_sample.crg", FileMode.Open, FileAccess.Read);
using var reader = new BinaryReader(fileStream);
var newLine = '\n';
var markerString = "$$$$";
var currentString = "";
var foundMarker = false;
var foundNewLine = false;
while (!foundNewLine)
{
var c = reader.ReadChar();
if (!foundMarker)
{
currentString += c;
if (currentString.Length > markerString.Length)
currentString = currentString.Substring(1);
if (currentString == markerString)
foundMarker = true;
}
else
{
if (c == newLine)
foundNewLine = true;
}
}
if (foundNewLine)
{
// Read binary
}
注意:如果您正在处理更大或更复杂的文件,您可能应该查看Mark Gravell的回答和评论部分。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.