不使用循环从文件中读取非字节数组?

3
有没有一种方法可以像在C语言中那样,将二进制数据从文件读入数组中,并且可以传递任何类型的指针到I/O函数中?我想到了类似于BinaryReader::ReadBytes()这样的东西,但是它返回的是byte[]类型,我无法将其转换为所需的数组指针类型。

1
你想要读取什么内容并对其进行什么操作?如果你想要读取图像,.NET有很好的库可以实现。 - Shadow The Spring Wizard
实际上我想读取一个 short[] 数组,但是 BinaryReader 只提供 byte[] ReadBytes(...)。我来自 C/C++,在那里我可以通过将其地址(引用)传递给读取函数来按字节读取(几乎)所有内容。 - Razzupaltuff
3个回答

5
如果您有一个固定大小的结构体
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct MyFixedStruct
{
  //..
}

您可以使用以下方法一次性读取它:

public static T ReadStruct<T>(Stream stream)
{
    byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
    stream.Read(buffer, 0, Marshal.SizeOf(typeof(T)));
    GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    T typedStruct = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    handle.Free();
    return typedStruct;
}

这段代码读取一个字节数组,其大小覆盖了struct的大小,然后将字节数组转换为结构体。可以按照以下方式使用:

MyFixedStruct fixedStruct =  ReadStruct<MyFixedStruct>(stream);

struct可以包含数组类型,只要指定了数组长度,如下:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct MyFixedStruct
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public int[] someInts; // 5 int's
    //..
};

编辑:

我看到您只想读取一个short数组 - 在这种情况下,只需读取字节数组并使用Buffer.BlockCopy()进行转换即可获得所需的数组:

byte[] someBytes = ..
short[] someShorts = new short[someBytes.Length/2];
Buffer.BlockCopy(someBytes, 0, someShorts, 0, someBytes.Length);

这种方法非常高效,相当于底层使用C++中的memcpy。当然,你所拥有的唯一额外开销是原始字节数组将被分配和稍后进行垃圾回收。这种方法也适用于任何其他原始数组类型。


好的,这可能有效,但(虽然这不是你的错)它是一个荒谬的开销。 - Razzupaltuff
@karx11erx:根据您的评论更新了答案,您只需要一个“short”数组。这种方法也适用于任何其他原始数组类型。 - BrokenGlass
好的,BlockCopy()...你提到它后我现在记得了(我正在通过将我的一个较小的C++应用程序移植到C#来学习C#,所以我还不像在C++中那样熟记所有这些东西)。谢谢你的解释。 - Razzupaltuff

0

将序列化的结构数组存储在文件中如何?您可以轻松地构建结构体数组。不确定如何像在C中那样流式传输文件。


我不能简单地序列化数组,因为我正在使用遗留数据格式。 - Razzupaltuff

-1

使用流类如何?它为字节序列提供了通用视图。


我不一定想读取一个字节数组。我在我的问题中写了那个。 - Razzupaltuff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接