【问题标题】:Data from byte array来自字节数组的数据
【发布时间】:2012-11-28 13:15:20
【问题描述】:

我正在尝试在每一帧读取流中的字节。 我希望能够读取存储在我创建的文件中的位置和时间戳信息。

流是记录的骨架数据流,采用编码二进制格式

Stream recordStream;
byte[] results;
using (FileStream SourceStream = File.Open(@".....\Stream01.recorded", FileMode.Open))
{
    if (SourceStream.CanRead)
    {
        results = new byte[recordStream.Length];
        SourceStream.Read(results, 0, (int)recordStream.Length);
    }
}

应该读取文件并且Read方法应该在推进流中的位置之前读取当前的字节序列。

有没有办法从读取的字节中提取我想要的数据(位置和时间戳),并在它前进之前将其保存在单独的变量中?

可以使用二进制阅读器给我这样做的能力。

BinaryReader br1 = new BinaryReader(recordStream);

我已将文件另存为 .recorded。我也把它保存为.txt,看看文件里有什么,但由于是编码的,所以看不懂。

更新: 我尝试使用断点运行代码以查看它是否使用我的 binaryreader 进入函数并崩溃并出现错误:ArgumentException 未处理。流不可读,在 BinaryReader 初始化和声明时

BinaryReader br1 = new BinaryReader(recordStream);

文件类型为 .recorded。

【问题讨论】:

  • 这完全取决于二进制文件的格式。您有可用的文件格式定义吗?它是二进制的事实意味着您需要寻找指定的目的地并从那里读取..
  • 文件格式为骨架数据流,包含时间戳(long 类型)、帧数(int 类型)、地板剪辑平面(float 类型)、包含设置的跟踪状态的骨架数据数组,跟踪id(int类型),骨架位置(float类型),关节信息,骨骼方向等........我如何寻找指定的目的地从那里读取?
  • 您更新的问题,即使相关,也应与此问题分开以避免混淆。

标签: c# file stream binary kinect


【解决方案1】:

您没有提供有关您尝试读取的数据格式的任何信息。
但是,使用 BinaryReader 正是您需要做的。

它公开了从流中读取数据并将其转换为各种类型的方法。
考虑以下示例:

var filename = "pathtoyourfile";

using (var stream = File.Open(filename, FileMode.Open))
using(var reader = new BinaryReader(stream))
{
    var x = reader.ReadByte();
    var y = reader.ReadInt16();
    var z = reader.ReadBytes(10);
}

不过,这实际上取决于您的数据格式。

更新
尽管我觉得我已经提供了你需要的所有信息, 让我们使用您的数据。

您说数据中的每条记录都以

开头

[long:timestamp][int:framenumber]

using (var stream = File.Open(filename, FileMode.Open))
using(var reader = new BinaryReader(stream))
{
    var timestamp = reader.ReadInt64();
    var frameNumber = reader.ReadInt32();

    //At this point you have the timestamp and the frame number
    //you can now do whatever you want with it and decide whether or not
    //to continue, after that you just continue reading
}

您如何继续阅读取决于记录剩余部分的格式 如果记录中的所有字段都有特定的长度,那么您要么(取决于 您在知道时间戳和帧号的值的情况下做出的选择)继续 读取该记录的所有字段,或者您只需前进到流中的某个位置 包含下一条记录。例如,如果每条记录是 100 字节长,如果你想在获得前两个字段后跳过这条记录:

stream.Seek(88, SeekOrigin.Current); 
//88 here because the first two fields take 12 bytes -> (100 - 8 + 4)

如果记录具有可变长度,则解决方案类似,但您必须 考虑到各个字段的长度(应该由 可变长度字段之前的长度字段)

至于知道前 8 个字节是否真的代表时间戳, 没有真正的方法可以确定...记住最后流只包含 一系列单独的字节,除了意义之外没有任何意义 通过您的文件格式提供给他们。要么你必须修改文件格式,要么你可以 尝试检查上面示例中的 'timestamp' 的值是否有意义。

这是您自己定义的文件格式吗?如果是...也许您正在使它变得复杂,并且可能想要查看诸如 Google Protocol Buffers 或 Apache Thrift 之类的解决方案。

如果这仍然不是您想要的,您将不得不重新定义您的问题。

【讨论】:

  • 数据以编码二进制格式记录,包含时间戳(long 类型)、帧数(int 类型)、地板剪辑平面(float 类型)、包含跟踪状态的骨架数据数组设置,跟踪id(int类型),骨架位置(float类型),关节信息,骨骼方向等......,正如我上面评论中提到的......如果包含这么多信息我怎么知道在前进之前只读取位置和时间戳(如果可能)。
【解决方案2】:

根据您的 cmets:

您需要知道整个文件的确切定义。您基于此文件格式创建结构:

struct YourFileFormat {
    [FieldOffset(0)]
    public long Timestamp;

    [FieldOffset(8)]
    public int FrameNumber;

    [FieldOffset(12)]
    //.. etc..
}

然后,使用BinaryReader,您可以为每个帧单独读取每个字段:

// assume br is an instantiated BinaryReader..
YourFileFormat file = new YourFileFormat();

file.Timestamp = br.ReadInt64();
file.FrameNumber = br.ReadInt32();
// etc..

或者,您可以读取整个文件并让编组类为您将所有内容复制到结构中..

byte[] fileContent = br.ReadBytes(sizeof(YourFileFormat));

GCHandle gcHandle = GCHandle.Alloc(fileContent, GCHandleType.Pinned); // or pinning it via the "fixed" keyword in an unsafe context
file = (YourFileFormat)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof(YourFileFormat));
gcHandle.Free();

但是,这假设您知道文件的确切大小。但是使用这种方法.. 每一帧(假设你知道有多少)可以是这个结构中的一个固定大小的数组,以便它工作。

底线:除非您知道要跳过的内容的大小..您不能希望从您需要的文件中获取数据。

【讨论】:

  • 我同意,但是是否有可能知道您读取的前 4 个字节是时间戳(长类型)还是推进之前的其他内容。有没有办法检查它是什么类型(在那里以二进制编码)并使用正确的二进制读取器方法来调用。所有 read 方法类型在被调用后都会前进,但我只想在它真正获得我想要的信息时前进,并跳过那些我不想要的。
  • 没有。如果你读了一个long,但数据应该被读为两个int's..那么你已经失败了。这就是文件格式有定义的原因。所以你知道会发生什么以及以什么顺序读取它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-17
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多