用C#實現Blob數據類型
PowerBuilder提供了Blob數據類型, 用來處理二進制數據(如:圖像,文件,二進制流,文本等等). 本質上, Blob是可變長的字節數組, 它提供了一系列全局函數來讀/寫Blob對象:
Blob : 將字符串轉換為Blob對象
BlobEdit : 將任意PowerBuilder基礎類型數據寫入Blob對象
BlobMid : 從Blob對象中讀取指定長度的數據,並返回Blob對象
Len : 求Blob對象的長度
請按說明文檔, 用C#實現命名,功能,行為,數據結果兼容PowerBuilder的Blob類型. 注: 為兼容PowerBuilder, 代碼不應拋出異常.
附:說明文檔
1.PowerBuilder基礎數據類型--------------------------------------------------------------------
Standard datatypes
The datatypes
The standard datatypes in PocketBuilder are the familiar datatypes that are used in many programming languages, including char, integer, decimal, long, and string. In PowerScript, you use these datatypes to declare variables or arrays.
These are the standard PowerScript datatypes, followed by a description of each:
Blob
Binary large object. Used to store an unbounded amount of data (for example, generic binary, image, or large text such as a word-processing document).
Boolean
Contains TRUE or FALSE.
Char or character
A single ASCII character.
If you have character-based data that you will want to parse in an application, you might want to define it as an array of type char. Parsing a char array is easier and faster than parsing strings. If you will be passing character-based data to external functions, you might want to use char arrays instead of strings.
For more information about passing character-based data to external functions, see the Resource Guide. For information about datatype conversion when assigning strings to chars and vice versa, see “String and char datatypes in PocketBuilder”.
Using literals To assign a literal value, enclose the character in either single or double quotation marks. For example:
char c
c = 'T'
c = "T"
Date
The date, including the full year (1000 to 3000), the number of the month (01 to 12), and the day (01 to 31).
Using literals To assign a literal value, separate the year, month, and day with hyphens. For example:
1992-12-25 // December 25, 1992
1995-02-06 // February 6, 1995
DateTime
The date and time in a single datatype, used only for reading and writing DateTime values from and to a database. To convert DateTime values to datatypes that you can use in PocketBuilder, use:
· The Date(datetime) function to convert a DateTime value to a PocketBuilder date value after reading from a database
· The Time(datetime) function to convert a DateTime value to a PocketBuilder time value after reading from a database
· The DateTime (date, time) function to convert a date and (optional) time to a DateTime before writing to a DateTime column in a database.
Decimal or Dec
Signed decimal numbers with up to 18 digits. You can place the decimal point anywhere within the 18 digits—for example, 123.456, 0.000000000000000001 or 12345678901234.5678.
Using literals To assign a literal value, use any number with a decimal point and no exponent. The plus sign is optional (95 and +95 are the same). For numbers between zero and one, the zero to the left of the decimal point is optional (for example, 0.1 and .1 are the same). For whole numbers, zeros to the right of the decimal point are optional (32.00, 32.0, and 32. are all the same). For example:
12.34 0.005 14.0 -6500 +3.5555
Double
A signed floating-point number with 15 digits of precision and a range from 2.2250738585073E-308 to 1.79769313486231E+308.
Integer or Int
16-bit signed integers, from -32768 to +32767.
Using literals To assign a literal value, use any whole number (positive, negative, or zero). The leading plus sign is optional (18 and +18 are the same). For example:
1 123 1200 +55 -32
Long
32-bit signed integers, from -2147483648 to +2147483647.
Using literals Use literals as for integers, but longer numbers are permitted.
LongLong
64-bit signed integers, from -9223372036854775808 to 9223372036854775807.
Using literals Use literals as for integers, but longer numbers are permitted.
Real
A signed floating-point number with six digits of precision and a range from 1.175495E-38 to 3.402822E+38.
Using literals To assign a literal value, use a decimal value, followed by E, followed by an integer; no spaces are allowed. The decimal number before the E follows all the conventions specified above for decimal literals. The leading plus sign in the exponent (the integer following the E) is optional (3E5 and 3E+5 are the same). For example:
2E4 2.5E78 +6.02E3 -4.1E-2
-7.45E16 7.7E+8 3.2E-45
String
Any ASCII character with variable length (0 to 2147483647).
Most of the character-based data in your application, such as names, addresses, and so on, will be defined as strings. PowerScript provides many functions that you can use to manipulate strings, such as a function to convert characters in a string to uppercase and functions to remove leading and trailing blanks.
For more information about passing character-based data to external functions, see the Resource Guide. For information about datatype conversion when assigning strings to chars and vice versa, see “String and char datatypes in PocketBuilder”.
Using literals To assign a literal value, enclose as many as 1024 characters in either single or double quotes, including a string of zero length or an empty string. For example:
string s1
s1 = 'This is a string'
s1 = "This is a string"
You can embed a quotation mark in a string literal if you enclose the literal with the other quotation mark. For example, the following statements result in the string Here's a string:
string s1
s1 = "Here's a string."
You can also use a tilde (~) to embed a quotation mark in a string literal. For example:
string s1 = 'He said, "It~'s good!"'
Complex nesting When you nest a string within a string that is nested in another string, you can use tildes to tell the parser how to interpret the quotation marks. Each pass through the parser strips away the outermost quotes and interprets the character after each tilde as a literal. Two tildes become one tilde, and tilde-quote becomes the quote alone.
Example 1 This string has two levels of nesting:
"He said ~"she said ~~~"Hi ~~~" ~" "
The first pass results in:
He said "she said ~"Hi ~" "
The second pass results in:
she said "Hi"
The third pass results in:
Hi
Example 2 A more probable example is a string for the Modify function that sets a DataWindow property. The argument string often requires complex quotation marks (because you must specify one or more levels of nested strings). To understand the quotation marks, consider how PocketBuilder will parse the string. The following string is a possible argument for the Modify function; it mixes single and double quotes to reduce the number of tildes:
"bitmap_1.Invert='0~tIf(empstatus=~~'A~~',0,1)'"
The double quotes tell PocketBuilder to interpret the argument as a string. It contains the expression being assigned to the Invert property, which is also a string, so it must be quoted. The expression itself includes a nested string, the quoted A. First, PocketBuilder evaluates the argument for Modify and assigns the single-quoted string to the Invert property. In this pass through the string, it converts two tildes to one. The string assigned to Invert becomes:
'0[tab]If(empstatus=~'A~',0,1)'
Finally, PocketBuilder evaluates the property’s expression, converting tilde-quote to quote, and sets the bitmap’s colors accordingly.
Example 3 There are many ways to specify quotation marks for a particular set of nested strings. The following expressions for the Modify function all have the same end result:
"emp.Color = ~"0~tIf(stat=~~~"a~~~",255,16711680)~""
"emp.Color = ~"0~tIf(stat=~~'a~~',255,16711680)~""
"emp.Color = '0~tIf(stat=~~'a~~',255,16711680)'"
"emp.Color = ~"0~tIf(stat='a',255,16711680)~""
Rules for quotation marks and tildes When nesting quoted strings, the following rules of thumb might help:
· A tilde tells the parser that the next character should be taken as a literal, not a string terminator
· Pairs of single quotes ( ' ) can be used in place of pairs of tilde double quotes (~")
· Pairs of tilde tilde single quotes (~~') can be used in place of pairs of triple tilde double quotes (~~~")
Time
The time in 24-hour format, including the hour (00 to 23), minute (00 to 59), second (00 to 59), and fraction of second (up to six digits), with a range from 00:00:00 to 23:59:59:999999.
Using literals The time in 24-hour format, including the hour (00 to 23), minute (00 to 59), second (00 to 59), and fraction of second (up to six digits), with a range from 00:00:00 to 23:59:59.999999. You separate parts of the time with colons—except for fractional sections, which should be separated by a decimal point. For example:
21:09:15 // 15 seconds after 9:09 pm
06:00:00 // Exactly 6 am
10:29:59 // 1 second before 10:30 am
10:29:59.9 // 1/10 sec before 10:30 am
UnsignedInteger, UnsignedInt, or UInt
16-bit unsigned integers, from 0 to 65535.
UnsignedLong or ULong
32-bit unsigned integers, from 0 to 4294967295.
2.Blob函數說明
Blob
--------------------------------------------------
Description
Converts a string to a blob datatype.
Syntax
Blob ( text )
Argument |
Description |
text |
The string you want to convert to a blob datatype |
Returns
Blob. Returns the converted string. If text is null, Blob returns null.
Examples
Example 1
This example saves a text string as a blob datatype:
Blob B
B = Blob("Any Text")
BlobEdit
--------------------------------------------------
Description
Inserts data of any PocketBuilder datatype into a blob variable.
Syntax
BlobEdit ( blobvariable, n, data )
Argument |
Description |
blobvariable |
An initialized variable of the blob datatype into which you want to copy a standard PocketBuilder datatype |
n |
The number (1 to 4,294,967,295) of the position in blobvariable at which you want to begin copying the data |
data |
Data of a valid PocketBuilder datatype that you want to copy into blobvariable |
Returns
Unsigned long. Returns the position at which the next data can be copied if it succeeds, and returns null if there is not enough space in blobvariable to copy the data. If any argument’s value is null, BlobEdit returns null.
If the data argument is a string, the position in the blobvariable in which you want to copy data will be the length of the string + 2. If the data argument is a string converted to a blob, the position will be the length of the string + 1. This is because a string contains a null terminating character that it loses when it is converted to a blob. Thus, BlobEdit (blob_var, 1, "ZZZ'') returns 5, while BlobEdit (blob_var, 1, blob (''ZZZ'') ) returns 4.
Examples
Example 1
This example copies a bitmap in the blob emp_photo starting at position 1, stores the position at which the next copy can begin in nbr, and then copies a date into the blob emp_photo after the bitmap data:
blob{1000} emp_photo
blob temp
date pic_date
ulong nbr
... // Read BMP file containing employee picture
... // into temp using FileOpen and FileRead.
pic_date = Today()
nbr = BlobEdit(emp_photo, 1, temp)
BlobEdit(emp_photo, nbr, pic_date)
UPDATEBLOB Employee SET pic = :emp_photo
WHERE ...
BlobMid
--------------------------------------------------
Description
Extracts data from a blob variable.
Syntax
BlobMid ( data, n {, length } )
Argument |
Description |
data |
Data of the blob datatype |
n |
The number (1 to 4,294,967,295) of the first byte you want returned |
length (optional) |
The number of bytes (1 to 4,294,967,295) you want returned |
Returns
Blob. Returns length bytes from data starting at byte n. If n is greater than the number of bytes in data, BlobMid returns an empty blob. If together length and n add up to more bytes than the blob contains, BlobMid returns the remaining bytes, and the returned blob will be shorter than the specified length. If any argument’s value is null, BlobMid returns null.
Include terminator characterString variables contain a zero terminator, which accounts for one byte. Include the terminator character when calculating how much data to extract.
Examples
Example 1
In this example, the first call to BlobMid stores 10 bytes of the blob datablob starting at position 5 in the blob data_1; the second call stores the bytes of datablob from position 5 to the end in data_2:
blob data_1, data_2, datablob
... // Read a blob datatype into datablob.
data_1 = BlobMid(datablob, 5, 10)
data_2 = BlobMid(datablob, 5)
Example 2
This code copies a bitmap in the blob emp_photo starting at position 1, stores the position at which the next copy can begin in nbr, and then copies a date into the blob emp_photo after the bitmap data. Then, using the date’s start position, it extracts the date from the blob and displays it in the StaticText st_1:
blob{1000} emp_photo
blob temp
date pic_date
ulong nbr
... // Read BMP file containing employee picture
... // into temp using FileOpen and FileRead.
pic_date = Today()
nbr = BlobEdit(emp_photo, 1, temp)
BlobEdit(emp_photo, nbr, pic_date)
st_1.Text = String(Date(BlobMid(emp_photo, nbr)))
String
--------------------------------------------------
Description
Converts data in a blob to a string value. If the blob’s value is not text data, String attempts to interpret the data as characters.
Syntax
String ( blob )
Argument |
Description |
blob |
The blob whose value you want returned as a string. Blob can also be an Any variable containing a blob. |
Returns
String. Returns the value of blob as a string if it succeeds and the empty string ("") if it fails. It the blob does not contain string data, String interprets the data as characters, if possible, and returns a string. If blob is null, String returns null.
Usage
You can also use String to extract a string from the Message object after calling TriggerEvent or PostEvent. For more information, see the TriggerEvent or PostEvent functions.
Examples
Example 18
This example converts the blob instance variable ib_sblob, which contains string data, to a string and stores the result in sstr:
string sstr
sstr = String(ib_sblob)
Example 19
This example stores today’s date and test status information in the blob bb. Pos1 and pos2 store the beginning and end of the status text in the blob. Finally, BlobMid extracts a "sub-blob" that String converts to a string. Sle_status displays the returned status text:
blob{100} bb
long pos1, pos2
string test_status
date test_date
test_date = Today()
IF DayName(test_date) = "Wednesday" THEN &
test_status = "Coolant Test"
IF DayName(test_date) = "Thursday" THEN &
test_status = "Emissions Test"
// Store data in the blob
pos1 = BlobEdit( bb, 1, test_date)
pos2 = BlobEdit( bb, pos1, test_status )
... // Some processing
// Extract the status stored in bb and display it
sle_status.text = String( &
BlobMid(bb, pos1, pos2 - pos1))
Len
Description
Reports the length of a string or a blob.
Syntax
Len ( stringorblob )
Argument |
Description |
stringorblob |
The string or blob for which you want the length in number of characters or in number of bytes |
Returns
Long. Returns a long whose value is the length of stringorblob if it succeeds and -1 if an error occurs. If stringorblob is null, Len returns null.
Usage
Len counts the number of characters in a string. The null that terminates a string is not included in the count.
If you specify a size when you declare a blob, that is the size reported by Len. If you do not specify a size for the blob, Len initially reports the blob’s length as 0. PowerBuilder assigns a size to the blob the first time you assign data to the blob. Len reports the length of the blob as the number characters it can contain.
Examples
Example 1
This statement returns 0:
Len("")
Example 2
These statements store in the variable s_address_len the length of the text in the SingleLineEdit sle_address:
long s_address_len
s_address_len = Len(sle_address.Text)
Example 3
The following scenarios illustrate how the declaration of blobs affects their length, as reported by Len.
In the first example, an instance variable called ib_blob is declared but not initialized with a size. If you call Len before data is assigned to ib_blob, Len returns 0. After data is assigned, Len returns the blob’s new length.
The declaration of the instance variable is:
blob ib_blob
Example 4
The sample code is:
long ll_len
ll_len = Len(ib_blob) // ll_len set to 0
ib_blob = Blob( "Test String")
ll_len = Len(ib_blob) // ll_len set to 22
Example 5
In the second example, ib_blob is initialized to the size 100 when it is declared. When you call Len for ib_blob, it always returns 100. This example uses BlobEdit, instead of Blob, to assign data to the blob because its size is already established. The declaration of the instance variable is:
blob{100} ib_blob
Example 6
The sample code is:
long ll_len
ll_len = Len(ib_blob) // ll_len set to 100
BlobEdit(ib_blob, 1, "Test String")
ll_len = Len(ib_blob) // ll_len set to 100