圖像數據在資料庫內部的存儲原理:
XML 是文本型的數據交換結構,對於字元類型的文本交換非常的方便,實際工作中我們往往需要通過 XML 將二進制格式的圖形圖像信息數據進行數據交換。本文從介紹 BASE64 編碼的原理入手,通過採用 C 語言編寫 DB2 的嵌入存儲過程,實現了在資料庫內存中將文本格式的圖片文件到二進制 BLOB 欄位之間的轉換,並且就性能優化等提出若干建議,該設計思路和程序可以廣泛的應用到圖像圖形數據在 XML 的存儲和轉換。
--------------------------------------------------------------------------------
回頁首
XML 存儲圖形圖像的基本原理
XML 作為一種非常廣泛的數據交換的載體被廣泛的應用到了各行各業的數據交換中。對於圖形圖像數據的轉換,需要採用 Base64 編碼將二進制格式的圖形圖像信息轉換成文本格式再進行傳輸。
Base64 編碼轉換的思想是通過 64 個 ASCII 字元碼對二進制數據進行重新編碼組合,即將需要轉換的數據每三個位元組(24 位)為一組,再將這 24 位數據按每組 6 位進行重新劃分,在每組的最高 2 位填充 0 最終成一個完整的 8 位位元組。如果所要編碼的數據的位元組數不是 3 的整數倍,需要在最後一組數據填充 1 到 2 個位元組的 0 位元組。例如:我們對 ABC 進行 BASE64 的編碼,ABC 的編碼值:A(65), B(66), C(67)。再取二進制 A(01000001)B(01000010)C(01000011)連接起來構成 010000010100001001000011,然後按 6 位為單位分成 4 個數據塊並在最高位填充兩個 0 後形成 4 個位元組的編碼後的值(00010000)(00010100)(00001001)(00000011)。再將 4 個位元組的數據轉換成十進制數為(16)(20)(19)(3)。最後根據 BASE64 給出的 64 個基本字元表,查出對應的 ASCII 碼字元(Q)(U)(J)(D)。這里的值實際就是數據在字元表中的索引。
BASE64 字元表:
。
某項目的數據交換採用 XML 的為介質,XML 的結構包括個人基本信息:姓名、性別、相片等信息,其中相片信息是採用經過 BASE64 函數轉換後的文本型數據,圖像圖形信息通過 BASE64 進行數據轉換後,形成文本格式的數據類型,再將相應的數據存放到 XML 中,最終形成可供交換的文本型的 XML 數據結構。
XML 的數據結構如下所示:
<?xml version=」1.0」 encoding=」UTF-8」 ?>
<HeadInfo>
<TotalNum>10<TotalNum>
<TransDate>2007-10-18</TransDate>
</HeadInfo>
<Data>
<Name> 張三 </Name>
<Sex> 男 </Sex>
<Photo>/9j/4AAQSkZJRgABAQAAAQABAAD......</Photo>
<Data>
--------------------------------------------------------------------------------
回頁首
相片數據在 DB2 嵌入式 C 程序的實現方法
該項目要求能夠在 DB2 資料庫中將相片數據存儲為二進制 BLOB 格式。我們採用 DATASTAGE 進行 XML 數據載入,將 XML 中的姓名、性別等基本數據項載入到相應的欄位,其中文本型的相片數據則載入到 CLOB 欄位中,再按照 BASE64 的編碼規則進行逆向轉碼,整個數據流程如下圖所示:
圖 1. 相片存儲流程圖
用戶的相片每天的更新數據為 30 萬條,而且每個相片的平均大於 32KB,為了獲得最佳的資料庫性能,選擇採用 C 存儲過程的方式開發了 BASE64 的轉換函數。每次函數讀取存儲在 CLOB 欄位的文本格式數據全部存儲到內存中,並且通過 decode 函數在內存中進行轉碼,轉碼後再存入資料庫中。
程序的清單 1 是逐行讀取 CLOB 欄位,並且調用 decode 函數進行轉碼;程序的清單 2 是 decode 函數的關鍵性代碼。完整的程序見源代碼下載部分。
清單 1. 讀入 CLOB,寫入 BLOB 欄位
EXEC sql BEGIN DECLARE SECTION;
SQL TYPE IS CLOB(100 K) clobResume; //CLOB 結構體變數
SQL TYPE IS BLOB(100 K) blobResume; //BLOB 結構體變數
sqlint16 bobind;
sqlint16 lobind;
sqlint16 cobind;
sqlint32 idValue;
EXEC SQL END DECLARE SECTION;
int clob2bin(void)
{
// 聲明 SQLCA 結構
struct sqlca sqlca;
int charNb;
int lineNb;
long n;
n=0;
// 定義資料庫游標
EXEC SQL DECLARE c1 CURSOR WITH HOLD FOR
SELECT czrkxp_a
FROM CZRK_blob for update;
EXEC SQL OPEN c1;
// 活動 CLOB 欄位的信息,已經 CLOB 欄位的大小
EXEC SQL FETCH c1 INTO :clobResume:cobind;
// 循環讀取 CLOB 欄位,並且調用 DECODE 轉碼函數
while (sqlca.sqlcode != 100)
{
if (cobind < 0)
{
printf(「 NULL LOB indicated.\n」);
}
else
{
n++;
decode(); // 文本格式到二進制流的轉碼函數
printf(「\nCurrent Row =%ld」,n);
// 數據寫入 BLOB 欄位
EXEC SQL update czrk_blob set czrkxp_blob = :blobResume
where current of c1; ;
// 提交事務
EXEC SQL COMMIT;
}
EXEC SQL FETCH c1 INTO :clobResume:cobind ;
}
// 關閉游標
EXEC SQL CLOSE c1;
EXEC SQL COMMIT;
return 0;
}
清單 2. 文本文件到二進制文件的轉換
void decode( void )
{
unsigned char in[4], out[3], v;
int I, len;
long j,k;
j = -1;
k=0;
// 將讀入 CLOB 結構體變數的數據進行轉換
while( j < clobResume.length){
for( len = 0, I = 0; I < 4 && ( j < clobResume.length ); i++ ) {
v = 0;
while((j < clobResume.length) && v == 0 ) {
j++;
v = (unsigned char) clobResume.data[j];
v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v – 43 ]);
if( v ) {
v = (unsigned char) ((v == 『$』) ? 0 : v – 61);
}
}
if( j < clobResume.length ) {
len++;
if( v ) {
in[ I ] = (unsigned char) (v – 1);
}
}
else {
in[i] = 0;
}
}
if( len ) {
decodeblock( in, out );
// 寫入到 BLOB 結構體變數中
for( I = 0; I < len – 1; i++ ) {
blobResume.data[k] = out[i];
k++;
}
}
}
blobResume.length= k;
}
--------------------------------------------------------------------------------
回頁首
數據的轉換效率和優化建議
在 IBM P570 資料庫伺服器上運行,該程序的運行效率非常高,先後進行了幾個數量級的測試,最終平均測試的轉換效率為:每 1 萬筆數據記錄,轉換的效率 55 秒,即 182 條 / 秒。值得注意的是,整個轉換過程佔用 CPU 的量並不特別大,主要的性能瓶頸在磁碟陣列中。
以後可以進一步在以下方面進行調優,確保程序轉換的效率更高:
1)採用多進程調用的方式,以獲得更高的並發數量;
2)採用每 10 次或者 100 次提交事務的方式,減少訪問磁碟的次數;
3)將 CLOB 和 BLOB 分別放置在不同的表空間上,並且將表空間分布在在多個磁碟上,獲得最佳的磁碟訪問速度。
㈡ c語言關於從資料庫讀取數據寫文件
#include<stdio.h>
execsqlincludesqlca;
intmain(){
execsqlbegindeclaresection;
charuserpasswd[30]="openlab/123456";
struct{
intid;
charname[30];
doublesalary;
}emp;
execsqlenddeclaresection;
execsqlconnect:userpasswd;
selectid,first_name,salaryfrom
s_emporderbysalary;
execsqlopenempcursor;
;
for(;;){
execsqlfetchempcursorinto:emp;
printf("%d:%s:%lf ",emp.id,emp.name,
emp.salary);
}
execsqlcloseempcursor;
execsqlcommitworkrelease;
}
把數據存到結構體里。
㈢ C語言環境下如何使用動態SQL
你真是牛人呀。資料庫類型那麼多,有oraclemysqlDB2SQLSQLsevera。你使用的那種。
相對於來說我使用oracle多。
給你一個pro*c的操作實例吧
/ 定義符號常數
#define USERNAME "SCOTT"
#define PASSWORD "x"
#include <stdio.h>
// 說明SQLCA和ORACA
EXEC SQL INCLUDE SQLCA;
EXEC SQL INCLUDE ORACA;
// 啟用ORACLE通訊區:ORACA=YES,使它能被使用
EXEC ORACLE OPTION (ORACA=YES);
// 說明SQL變數
EXEC SQL BEGIN DECLARE SECTION;
char* username=USERNAME;
char* password=PASSWORD;
VARCHAR sqlstmt[80];
int emp_number;
VARCHAR emp_name[15];
VARCHAR job[50],job1[50],job2[50];
float salary;
EXEC SQL END DECLARE SECTION;
main()
{
EXEC SQL WHENEVER SQLERROR GOTO sqlerror;
// 發生錯誤時,保存SQL語句至ORACA
oraca.orastxtf=ORASTFERR;
// 登錄到ORACLE
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf("/nConnect to ORACLE./n");
// 構造動態SQL語句
sqlstmt.len=sprintf(sqlstmt.arr,"INSERT INTO EMP(EMPNO,ENAME,JOB,SAL)VALUES(:V1,:V2,:V3,:V4)");
// 顯示SQL語句
puts(sqlstmt.arr);
// 用PREPARE語句分析當前的動態INSERT語句,語句名是S
EXEC SQL PREPARE S FROM :sqlstmt;
// 循環插表
for(;;)
{
printf("/nEnter employee number:");
scanf("%d",&emp_number);
if(emp_number==0)break;
printf("/nEnter employee name:");
scanf("%s",&emp_name.arr);
emp_name.len=strlen(emp_name.arr);
printf("/nEnter employee job:");
scanf("%s",&job.arr);
job.len=strlen(job.arr);
salary = 0; // With VC6, Missing this line will cause C Run-Time Error R6002.
printf("/nEnter salary:");
scanf("%f",&salary);
EXEC SQL EXECUTE S USING :emp_number,:emp_name,:job,:salary;
}
// 提交事務,退出ORACLE
EXEC SQL COMMIT RELEASE;
printf("/nHave a good day!/n");
exit(0);
sqlerror:
// 列印錯誤信息
printf("/n%.*s/n",sqlca.sqlerrm.sqlerrml,sqlca.sqlerrm.sqlerrmc);
// 列印出錯SQL語句
printf("/n/"%.*s.../"/n",oraca.orastxt.orastxtl,oraca.orastxt.orastxtc);
// 列印出錯SQL語句所在行號及所在文件名
printf("on line %d of %.*s/n/n",oraca.oraslnr,
oraca.orasfnm.orasfnml,oraca.orasfnm.orasfnmc);
// 回滾事務,退出ORACLE
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
㈣ linux下c++遠程連接oracle資料庫
你說的復合結構應該是結構體吧。若是舉個例子給你看看
/*
* sample2.pc
*
* This program connects to ORACLE, declares and opens a cursor,
* fetches the names, salaries, and commissions of all
* salespeople, displays the results, then closes the cursor.
*/
#include <stdio.h>
#include <sqlca.h>
#define UNAME_LEN 20
#define PWD_LEN 40
/*
* Use the precompiler typedef』ing capability to create
* null-terminated strings for the authentication host
* variables. (This isn』t really necessary--plain char *』s
* does work as well. This is just for illustration.)
*/
typedef char asciiz[PWD_LEN];
EXEC SQL TYPE asciiz IS STRING(PWD_LEN) REFERENCE;
asciiz username;
asciiz password;
struct emp_info
{
asciiz emp_name;
float salary;
float commission;
};
/* Declare function to handle unrecoverable errors. */
void sql_error();
main()
{
struct emp_info *emp_rec_ptr;
/* Allocate memory for emp_info struct. */
if ((emp_rec_ptr =
(struct emp_info *) malloc(sizeof(struct emp_info))) == 0)
{
fprintf(stderr, "Memory allocation error. ");
exit(1);
}
/* Connect to ORACLE. */
strcpy(username, "SCOTT");
strcpy(password, "TIGER");
EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--");
EXEC SQL CONNECT :username IDENTIFIED BY :password;
printf(" Connected to ORACLE as user: %s ", username);
/* Declare the cursor. All static SQL explicit cursors
* contain SELECT commands. 』salespeople』 is a SQL identifier,
* not a (C) host variable.
*/
EXEC SQL DECLARE salespeople CURSOR FOR
SELECT ENAME, SAL, COMM FROM EMP WHERE JOB LIKE 』SALES%』;
/* Open the cursor. */
EXEC SQL OPEN salespeople;
/* Get ready to print results. */
printf(" The company』s salespeople are-- ");
printf("Salesperson Salary Commission ");
printf("----------- ------ ---------- ");
/* Loop, fetching all salesperson』s statistics.
* Cause the program to break the loop when no more
* data can be retrieved on the cursor.
*/
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
EXEC SQL FETCH salespeople INTO :emp_rec_ptr;
printf("%-11s%9.2f%13.2f ", emp_rec_ptr->emp_name,emp_rec_ptr->salary, emp_rec_ptr->commission);
}
/* Close the cursor. */
EXEC SQL CLOSE salespeople;
printf(" Arrivederci. ");
EXEC SQL COMMIT WORK RELEASE;
exit(0);
}
void sql_error(msg) char *msg;
{
char err_msg[512];
int buf_len, msg_len;
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf(" %s ", msg);
/* Call sqlglm() to get the complete text of the
* error message.
*/
buf_len = sizeof (err_msg);
sqlglm(err_msg, &buf_len, &msg_len);
printf("%.*s ", msg_len, err_msg);
EXEC SQL ROLLBACK RELEASE;
exit(1);
}
㈤ C語言db2嵌入式SQL編程,編譯問題 undefined reference to `sqlastrt'
1、要有類似的定義:
……
EXEC SQL INCLUDE SQLDA; /* or #include <sqlda.h> */
2、編譯環境要有db2的許可權和sqllib的路徑
3、我已經上傳了一份相關的文檔,預計明後天審核通過就可以看到了
《DB2開發基礎》
http://passport..com/?business&aid=6&un=chinacmouse#7
補充一個程序:
#include <time.h>
#include "stdio.h"
EXEC SQL INCLUDE SQLCA;
int main()
{
int i=0;
struct tm *pt;
time_t t1;
t1 = time(NULL);
pt = localtime(&t1);
printf("%4d%02d%02d", pt->tm_year+1900, pt->tm_mon+1, pt->tm_mday);
printf("%02d:%02d:%02d\n",pt->tm_hour,pt->tm_min,pt->tm_sec);
EXEC SQL CONNECT TO db;
i=0;
while (i<3000)
{
int j=0;
while (j<1000)
{
EXEC SQL update cc.fund set cc_code='095' where cc_no='0950031359';
j++;
}
i++;
}
EXEC SQL COMMIT;
t1 = time(NULL);
pt = localtime(&t1);
printf("%4d%02d%02d", pt->tm_year+1900, pt->tm_mon+1, pt->tm_mday);
printf("%02d:%02d:%02d\n",pt->tm_hour,pt->tm_min,pt->tm_sec);
EXEC SQL CONNECT RESET;
return 1;
}
編譯腳本:
db2 prep testdb.sqc target cplusplus bindfile using testdb.bnd package using testdb
db2 bind testdb.bnd
db2 grant execute on package testdb to public
gcc -I/app/db2inst1/sqllib/include -I./ -c -g testdb.C
gcc -L/app/db2inst1/sqllib/lib -ldb2 -L/usr/lib -lm -o testdb testdb.o