我有一個CLOB列的大表。文本數據現在存儲在其中。但我想寫二進制字符串。在這種情況下,我會遇到一些麻煩嗎?我可以在CLOB列中存儲二進制字符串嗎
編輯:
遷移到BLOB是不恰當的 - 該表是非常大的。
我有一個CLOB列的大表。文本數據現在存儲在其中。但我想寫二進制字符串。在這種情況下,我會遇到一些麻煩嗎?我可以在CLOB列中存儲二進制字符串嗎
編輯:
遷移到BLOB是不恰當的 - 該表是非常大的。
一般來說,你不能這樣做。特別是如果你的數據庫使用UTF-8(默認現在),你有不匹配的有效字符許多位值,他們將用一個佔位符(通常¿
),而插入,然後選擇所取代。
你可以做的是將你的二進制數據編碼爲Base64字符串。這是在接口傳輸二進制數據很常見的方式僅支持文本(例如XML文件或SMTP郵件)
使用此功能進行編碼的二進制數據,文本:
FUNCTION EncodeBASE64(InBlob IN BLOB) RETURN CLOB IS
lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
BlobLen INTEGER := DBMS_LOB.GETLENGTH(InBlob);
read_offset INTEGER := 1;
warning INTEGER;
amount INTEGER := 1440; -- must be a whole multiple of 3
-- size of a whole multiple of 48 is beneficial to get NEW_LINE after each 64 characters
buffer RAW(1440);
res CLOB := EMPTY_CLOB();
BEGIN
IF InBlob IS NULL OR NVL(BlobLen, 0) = 0 THEN
RETURN NULL;
ELSIF BlobLen <= 24000 THEN
RETURN UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(InBlob));
ELSE
-- UTL_ENCODE.BASE64_ENCODE is limited to 32k, process in chunks if bigger
LOOP
EXIT WHEN read_offset >= BlobLen;
DBMS_LOB.READ(InBlob, amount, read_offset, buffer);
res := res || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(buffer));
read_offset := read_offset + amount;
END LOOP;
END IF;
RETURN res;
END EncodeBASE64;
而且此功能轉換回成團塊
FUNCTION DecodeBASE64(InBase64Char IN CLOB) RETURN BLOB IS
res BLOB;
clob_trim CLOB;
dest_offset INTEGER := 1;
src_offset INTEGER := 1;
read_offset INTEGER := 1;
ClobLen INTEGER := DBMS_LOB.GETLENGTH(InBase64Char);
amount INTEGER := 1440; -- must be a whole multiple of 4
buffer RAW(1440);
stringBuffer VARCHAR2(1440);
-- BASE64 characters are always simple ASCII. Thus you get never any Mulit-Byte character and having the same size as 'amount' is sufficient
BEGIN
IF InBase64Char IS NULL OR NVL(ClobLen, 0) = 0 THEN
RETURN NULL;
ELSIF ClobLen <= 32000 THEN
RETURN TO_BLOB(UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(InBase64Char)));
ELSE
-- Remove all NEW_LINE from base64 string
DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL);
DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer);
read_offset := read_offset + amount;
END LOOP;
read_offset := 1;
ClobLen := DBMS_LOB.GETLENGTH(clob_trim);
DBMS_LOB.CREATETEMPORARY(res, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset)));
DBMS_LOB.WRITEAPPEND(res, DBMS_LOB.GETLENGTH(buffer), buffer);
read_offset := read_offset + amount;
END LOOP;
DBMS_LOB.FREETEMPORARY(clob_trim);
END IF;
RETURN res;
END DecodeBASE64;
您在能上網的地方,你可以驗證你的程序發現許多網上的Base64解碼/編碼器。
感謝您的詳細解答。我的數據庫使用CP1251,現在我使用base64來存儲數據。我做了一些測試,但沒有看到任何異常現象。 –
對二進制數據使用blob列。 – Rene
我可以將二進制數據編碼爲普通字符串,但我無法更改列類型。 –