繁体   English   中英

C# - 从特定字符串的文件中读取字节

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM