我有很多非常大的矩阵(有时是双精度的,但也许是其他类型的),它们的尺寸可以变化。我想将整个数组存储为varbinary(max)
我可以很好地存储记录(我认为)。但是,当我读取数据时,可以创建一个具有多个维度的新的double数组。我可以从SQL读取存储的数据(我认为)。我现在不知道的是我使用的Buffer.BlockCopy()操作的逆过程。
SQL表如下所示:
create table test_varbinary_table(
id int not null IDENTITY PRIMARY KEY ,
name varchar(256) not null,
rows int not null,
cols int not null,
vb_data varbinary(max) null
)
用于存储数据的存储过程在这里: (已删除,因为可能只是使问题变得混乱) 编写示例记录的C#在这里: (已删除,因为我认为这部分有用,但我不知道它有助于解决问题)
GetData存储过程是这样的:
ALTER PROCEDURE [dbo].[GetData]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT * from test_varbinary_table
END
我用
阅读表格 try
{
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
SqlDataReader rdrMatrix = null;
DataTable tblMatrix = new DataTable();
using (SqlCommand cmd = new SqlCommand("dbo.GetData", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
rdrMatrix = cmd.ExecuteReader(CommandBehavior.CloseConnection);
tblMatrix.Load(rdrMatrix);
String strResult = "";
foreach (DataRow dr in tblMatrix.Rows)
{
int r = 2, c = 3;
double[,] dary = new double[r, c];
byte[] retData = new byte[6 * sizeof(double)];
String retName;
retName = dr["name"].ToString();
strResult += retName + "\r\n";
retData = (byte[])dr["vb_data"]; // potential problem?
Buffer.BlockCopy(retData, 0, dary, 0, dary.Length); // potential problem?
for (int ri = 0; ri< 2; ri++)
{
strResult += " ";
for (int ci = 0; ci<3; ci++)
{
strResult += " " + dary[ri,ci] ;
}
strResult += "\r\n";
}
strResult += "\r\n" ;
}
textBox1.Text = strResult;
}
conn.Close();
}
//textBox1.Text = "No Failure!";
}
对于写代码,我只是手动修改了内容以写一些不同的记录。当我检查SSMS中的表时,可以看到它已成功添加行。虽然无法读取字节流,但是如果更改数据,字节流确实会更改,如果不更改数据,字节流将保持不变。但是,当我运行c#代码读取记录时,每次……零都得到相同的结果。
输出如下:
foo
0 0 0
0 0 0
bar
0 0 0
0 0 0
因此,它要么无法读取@data字段,要么无法正确将其转换为byte []或blockcopy无法正常工作。 (我认为。)无论如何,它返回的都是零而不是我存储的数据。
答案 0 :(得分:0)
我能够使用BlockCopy解决该问题,将矩阵编码为可以写入varbinary的字节数组。读取时,我使用BitConverter从字节数组解码为double [,]。我不知道为什么我不能让BlockCopy在另一个方向上工作。我错过了一些东西。
无论如何,到目前为止,我的解决方案使用的代码略有不同,但这是必不可少的元素:
我存储矩阵的表:
CREATE TABLE [dbo].[test_varbinary_table](
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](8) NOT NULL,
[version] [varchar](16) NOT NULL,
[date] [datetime] NOT NULL,
[notes] [varchar](max) NULL,
[rows] [int] NOT NULL,
[cols] [int] NOT NULL,
[checksum] [float] NULL,
[vb_data] [varbinary](max) NULL
)
将double [,]编码为字节数组的方法,该数组将直接写入varbinary:
public byte[] DoubleMatrixToByteArray(double[,] doubleArray)
{
int rows = doubleArray.GetLength(0);
int cols = doubleArray.GetLength(1);
byte[] byteArray = new byte[rows * cols * sizeof(double)];
Buffer.BlockCopy(doubleArray, 0, byteArray, 0, byteArray.Length);
return byteArray;
}
从varbinary解码回2D双数组的方法:
public double[,] VarBinaryToDoubleMatrix (byte[] byteArray, int rows, int cols)
{
double[,] doubleArray = new double[rows, cols];
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
doubleArray[r,c] = BitConverter.ToDouble(byteArray, r * cols * sizeof(double) + c * sizeof(double));
}
}
return doubleArray;
}
校验和:
// Summation of all cells in a matrix, just a quick verification check.
// The intent is to verify that when a matrix is read from the database,
// the reconstructed matrix has the same checksum as the one that was saved.
//
public double computeChecksum(double[,] dblArray)
{
int rank = dblArray.Rank; // rank is the number of dimensions of an array.
int rows = dblArray.GetLength(0);
int cols = dblArray.GetLength(1);
double sum = 0.0;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
sum += dblArray[r, c];
}
}
return sum;
}
}
我用校验和保存数组,并与varbinary字段一起读取。然后,我重新计算校验和并将其与保存的校验和值进行比较。