使用 UltraLite 10 (C#) 读取和写入 Windows Mobile 数据库中的图像






4.67/5 (3投票s)
本文的目的是帮助那些希望使用 C# 和 UltraLite 在 Windows Mobile 应用程序中访问和存储图像的开发人员。

引言
我偶尔会收到关于如何在 Windows Mobile 上运行的数据库中读写二进制数据的请求。如果您在互联网上搜索,通常可以找到适用于 Windows 桌面或允许您读写本地文件系统的示例。问题在于,要使这些代码在 Windows Mobile 上访问数据库,需要做一些工作。
最终您可能会问,为什么我要将图像存储在数据库中?在本地移动数据库与集中式(中央)数据库之间同步数据的环境中,这可能非常有帮助。想象一下,保险理赔员去事故现场,拍摄了一张损坏汽车的照片,将其加载到他的 Windows Mobile 数据库中,然后将该图像复制到保险总部进行批准。当使用数据库中的图像时,所有这些都可以在很短的时间内完成。另一个很好的例子可能是等待病人图表可用性的医生。如果您可以将图像存储在数据库中,一旦图表可用,就可以将其发送到医生的设备上。
对于本文,我将不深入探讨如何将图像同步到远程中央数据库和从远程中央数据库同步,因为在使用 MobiLink 等数据同步技术时,这通常相当直接。
要求
对于此示例,我选择使用 UltraLite 作为本地数据库。我还使用 ADO.NET 来访问此数据库。因此,您需要以下组件才能开始使用:
- SQL Anywhere 10 开发者版: (请确保下载并安装 SQL Anywhere CE 组件)
- Visual Studio .NET 2005
- Windows Mobile 5 软件开发工具包(标准版和专业版)
入门
我包含了一个项目,其中应包含您开始所需的一切。如果您不熟悉 UltraLite 或如何添加命名空间引用,我建议您查阅我之前的文章:“使用 .NET 和 UltraLite 10 创建 Windows Mobile 数据库应用程序的 10 个步骤”。
创建 UltraLite 数据库
我们希望应用程序做的第一件事是连接到本地 UltraLite 数据库。有多种方法可以创建 UltraLite 数据库,例如:
- Sybase Central:用于配置所有 SQL Anywhere 10 组件的图形用户界面
- ULCREATE.exe:用于初始化新数据库的命令行实用程序
- 应用程序:您可以从应用程序内部执行代码来创建一个新数据库
对于此示例,我们将使用第三种方法并在应用程序中创建数据库。我们将通过检查文件是否存在来做到这一点。如果文件不存在,则会创建数据库和表。如果数据库已存在,则会创建连接,应用程序将打开。以下是用于在设备上创建数据库和表的代码:
// This will create a new database
ULConnectionParms openParms = new ULConnectionParms();
openParms.DatabaseOnCE = dbf;
// Assumes file %sqlany10%\src\ulcollations\cs\coll_1252LATIN1.cs is
// also compiled in the current project
ULConnection.DatabaseManager.CreateDatabase(
openParms.ToString(), Collation_1252LATIN1.Data, ""
);
ConnUL.ConnectionString = "dbf=" + dbf + ";cache_size=1M";
if (ConnUL.State != ConnectionState.Open)
{
ConnUL.Open();
}
ConnUL.DatabaseID = 1000;
// Create table to store images
string CreateDb = "create table images ( ";
CreateDb += "image_id integer default autoincrement, ";
CreateDb += "image_name varchar(30), ";
CreateDb += "image_binary long binary, ";
CreateDb += "primary key (image_id) ";
CreateDb += ")" ;
ULCommand cmd = new ULCommand(CreateDb, ConnUL);
cmd.ExecuteNonQuery();
从文件系统中读取文件
此应用程序的第一步将是允许用户从 Windows Mobile 设备中选择一个文件,然后加载它。以下代码概述了如何执行此操作:
private void menuSave_Click(object sender, EventArgs e)
{
// Open a file dialog to choose a file and then load the
// binary data into byte[] fileData
FileStream strm;
byte[] fileData = null;
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "All images|*.bmp *.jpeg *.jpg *.gif|All files
(*.*)|*.*|JPEG files (*.jpeg)|*.jpeg|JPG files (*.jpg)|*.jpg|Bitmap
files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
String fname = openFileDialog1.FileName;
int n;
string fullFileName = fname;
// lose the extension
n = fname.LastIndexOf('.');
if (n >= 0)
{
fname = fname.Substring(0, n);
}
// lose the path
n = fname.LastIndexOf('\\');
if (n >= 0)
{
fname = fname.Substring(n + 1);
}
myFile = fname;
try
{
strm = new FileStream(fullFileName, System.IO.FileMode.Open);
long iLength = strm.Length;
fileData = new byte[(int)strm.Length];
strm.Read(fileData, 0, (int)strm.Length);
strm.Close();
// add it to the DB (if not pre-canned)
bool return_code = SaveImage(fileData, iLength, myFile);
//Update the combo box
UpdateComboFileName();
comboFileName.Text = myFile;
ShowPreview();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
ShowPreview();
}
}
将图像加载到数据库
现在我们已经选择了文件并读取了它,我们希望将此文件流存储到数据库中。对于此示例,我们将将其存储在 LONG BINARY
列中。UltraLite 表的结构如下:
create table images (
image_id integer default autoincrement,
image_name varchar(30),
image_binary long binary,
primary key (image_id)
)
以下代码显示了如何获取二进制数据并将其插入数据库:
public bool SaveImage(byte[] fileData, long imageLen, String filename)
{
// Take the binary fileData and insert it into the database
ULParameter parm;
long RowsInserted;
try
{
using (ULCommand cmd = ConnUL.CreateCommand())
{
cmd.CommandText =
"INSERT INTO images(image_name, image_binary) VALUES (?, ?)";
cmd.Parameters.Add("image_name", filename);
parm = new ULParameter();
parm.ULDbType = ULDbType.Binary;
parm.Direction = ParameterDirection.Input;
parm.Value = fileData;
parm.Size = Convert.ToInt32(imageLen);
cmd.Parameters.Add(parm);
RowsInserted = cmd.ExecuteNonQuery();
}
}
catch (Exception err)
{
MessageBox.Show("Exception: " + err.Message);
}
return true;
}
从数据库中选择图像
既然我们已经将图像存储在数据库中,我们也希望能够显示它。为此,我们将使用一个组合框,其中将填充可以从数据库中检索到的文件列表。当用户选择一个文件时,将检索并显示相应的图像。一旦我选择了图像,我就选择使用 MemoryStream
来存储二进制数据。我看到的大多数示例都首先将其存储到本地文件系统,然后直接从那里加载。对我来说,这似乎效率极低,但我敢肯定,有比我更懂编程的人会告诉我他们为什么需要这样做。用于显示图像的底层代码如下:
private void ShowPreview()
{
// Based on the selected image filename, select the binary data for the
// image from the database and display it
try
{
using (ULCommand cmd = ConnUL.CreateCommand())
{
cmd.CommandText = "SELECT image_binary from images
WHERE image_name = '" + comboFileName.Text +"'";
ULDataReader rdr = cmd.ExecuteReader();
if (rdr.Read())
{
byte[] m_image = (byte[])rdr["image_binary"];
MemoryStream ms = new MemoryStream(m_image);
Bitmap bmap = new Bitmap(ms);
pbPreview.Image = (bmap);
}
rdr.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
部署和运行应用程序
附加的源文件包含编译和部署应用程序所需的所有代码。请注意,您可能需要重新附加位于...的 coll_1252LATIN1.cs 文件。
%sqlany10%\src\ulcollations\cs\coll_1252LATIN1.cs
...以及可能位于...的 ulnet10.dll 文件。
%sqlany10%\ultralite\UltraLite.NET\ce\arm\ulnet10.dll
摘要
图像正迅速成为移动应用程序的热门附加功能。如今,设备标配图像捕获设备,将图像存储到数据库的需求变得越来越重要。
在此示例中,我们使用 UltraLite 作为本地数据存储,但是由于该应用程序使用 ADO.NET 通过标准 SQL,因此该概念也同样适用于几乎任何 Windows Mobile 数据库。
历史
- 2007 年 5 月 28 日:首次发布