【发布时间】:2019-03-12 04:28:30
【问题描述】:
我正在处理从二进制文件中读取的一些数据,并且可以是几种原始类型之一,例如int16、int32、单、双等
例如,假设我有 3 个文件:
- 文件 A:包含所有 int16
- 文件 B:包含所有 int32
- 文件 C:包含所有单个
每个文件的标题都有一个数据类型的代码,例如,文件 A 会有一个标题字段 dtype: 0,文件 B 会有一个标题字段 dtype: 1,文件 C 会有一个标题字段 @987654323 @。
这些文件是专有的图像格式 - 想象一个位图,但位图的主体可能都是 int16、int32 或单个。
鉴于我已从二进制文件中读取数据,我使用模式匹配将二进制数据转换为文件头指定的类型。
假设我有一个数组/缓冲区,其中包含从文件流中读取的 n 个字节:
let buffer: byte[] = … <-- read bytes into here
let container = new ResizeArray<obj>() //maintain same type in pattern match
let matchDatatype (dtype: int) = // Let's read File B
match dtype with
| 0 ->
let typeBuffer: int16[] = numBytesInFile/2 |> Array.zeroCreate
while stream.Position < stream.Length do
stream.Read(buffer, 0, numBytesInFile) |> ignore
Buffer.BlockCopy(buffer, 0, typeBuffer, 0, numBytesInFile)
typeBuffer |> Array.chunkBySize 8 |> container.Add
| 1 -> // Reading int32 from File B
let typeBuffer: int32[] = numBytesInFile/4 |> Array.zeroCreate
while stream.Position < stream.Length do
stream.Read(buffer, 0, numBytesInFile) |> ignore
Buffer.BlockCopy(buffer, 0, typeBuffer, 0, numBytesInFile)
typeBuffer |> Array.chunkBySize 8 |> container.Add
| 2 -> ...
….
因此,如果我从文件 B 中读取,标头数据代码显示“将这些字节读取为 int32”,会发生其他一些事情,并且我有一个包含数组数组的 ResizeArray<obj>(例如 int[][])
要获得我需要的数组,我只需对 ResizeArray (container.[0]) 进行切片,然后得到一个 obj。
我需要将这个obj 恢复为数组类型。问题是,由于我正在读取多种可能类型的文件,因此无法将我的代码概括为适用于所有不同的文件。如果我知道该文件将包含所有整数,我知道我可以做到container.[0] :?> int[][],但我在设计时不知道。
我知道我不能将数组的类型存储为来自 GetType() 的 let 绑定,这进一步混淆了我应该如何处理这个问题(例如,container.[0] :?> container.[0].GetType() 不起作用)。
使用 fsi,如果我从文件 B (int) 中读取,这是我尝试做的一个示例:
> let someArray = [|[|0;1;2|];|[3;4;5|]|];; <-- say I read this from File B
val it : int [] [] = [|[|0; 1; 2|];[|3; 4; 5|]|]
> container.Add(someArray)
val it: unit = ()
> let arrObj = container.[0]
val it : obj = [|[|0; 1; 2|];[|3; 4; 5|]|]
> arrObj.GetType().FullName;;
val it : string = "System.Int32[][]"
> arrObj :?> int[][] <-- I can't know this at design time
val it : int [] [] = [|[|0; 1; 2|];[|3; 4; 5|]|]
最后一步是出现问题的地方。返回的类型对象清楚地表明它知道数组不是对象——它实际上是一个int[][]。如何以编程方式/动态执行此向下转换而不明确说“向下转换为int[][]?”我也需要它来处理 single[][] 和 int16[][] 的情况。
或者,在编写可以灵活读取不同类型数据的代码时,我的整个方法是否存在缺陷?我唯一的另一个想法是做一些尝试捕捉怪物,但我觉得这不是很惯用。
我之前的工作都是在 MATLAB 中完成的,所以这对我来说是一个新问题,因为我可以评估字符串并生成我需要的代码。
编辑:使用 Buffer.BlockCopy 代替 BitConverter
edit 2:我看到 F# 可以使用 type 定义类型别名,其中
[accessibility-modifier] type-abbreviation = type-name
但是,这不允许我做类似type ArrType = arrObj.GetType() 的事情。我能想到的最接近我认为我需要的是一个类似 C 的 typedef。
编辑 3:我一直在使用 Activator.CreateInstance() 研究一种称为动态实例化的东西 - 这是一个可以使用它的实例吗?
【问题讨论】:
-
目前还不清楚您真正想要做什么。您是否在阅读元素都是不同类型的,但又想以某种方式使它们成为一种类型?还是每个给定文件都只包含一种类型的元素?
-
@FyodorSoikin 每个给定文件只包含一种类型的元素。我会尝试在问题正文中清除它。
-
你希望对沮丧的结果做什么?
-
@kvb 由于文件中的数据代表 3D 或 4D 数组(文件格式是专有的医学成像格式,如果有帮助的话),我希望能够在数组。将数组作为 obj 不会让我这样做,并且代码无法知道数据是 int16、int32、single 等,直到解析文件头(幸运的是,我没有问题)。我担心来自 MATLAB/Mathematica 让我对一些更惯用的方法视而不见,但它让我无法理解。