Это основано на ответе mik, но я нашел в нем дыру, где добавление более одной строки шестнадцатеричного кода вводит дополнительный шестнадцатеричный символ 0 в начале каждой строки, когда вы используете HEXTORAW
в каждой строке добавления. Когда вы вытаскиваете этот шестнадцатеричный код обратно из базы данных и сравниваете его с тем, что, по вашему мнению, вы вставляли, вы видите это. Если шестнадцатеричный код был изображением, и вы привязываете эти байты изображения к Image.Source
, ноль игнорируется, если к нему добавлена только одна строка, но если у вас есть несколько строк, он вводит этот дополнительный байт для каждого фрагмента и повреждает ваши данные и вы не можете отобразить изображение. Я предполагаю, что то же самое происходит с обычными файлами и другими данными, которые вы хотите загрузить.
Вместо этого я добавил все свои шестнадцатеричные значения в CLOB, который сохраняет их как строку шестнадцатеричных значений, а также имеет тот же предел в 4 ГБ, что и поле BLOB. Таким образом, только эта неповрежденная строка записывается в BLOB как RAW
, когда шестнадцатеричная строка больше, чем ограничение в 32767 символов/байт:
DECLARE
buf BLOB;
cBuf CLOB;
BEGIN
dbms_lob.createtemporary(buf, FALSE);
dbms_lob.createtemporary(cBuf, FALSE);
dbms_lob.append(cBuf, '0EC1D7FA6B411DA5814');
--...lots of hex data...
dbms_lob.append(cBuf, '0EC1D7FA6B411DA5814');
-- now we append the CLOB of hex to the BLOB as RAW
dbms_lob.append(buf, HEXTORAW(cBuf));
UPDATE MyTable
SET blobData = buf
WHERE ID = 123;
END;
Мой сценарий заключался в том, что я использовал SQLite, по сути, как резервную базу данных, но мне по-прежнему требовался способ синхронизировать Oracle (моя основная база данных) при загрузке документа, когда соединение с ним можно было восстановить.
В качестве более полного ответа о том, как создать этот SQL программно, я подумал, что должен показать это, поскольку я сделал это со своим приложением. Код в моем приложении C# помещал байты файла в шестнадцатеричный формат, затем у меня была строковая переменная с приведенным выше SQL, которую я записывал в файл, а позже служба использовала ее для обновления Oracle при восстановлении соединения. Итак, вот как я разобрался, как я вставил свой шестнадцатеричный код в эту строку SQL и файл (а позже и в Oracle):
// This is all staged so someone can see how you might go from file
// to bytes to hex
string filePath = txtFilePath.Text; // example of getting file path after
// OpenFileDialog places ofd.FileName in a textbox called txtFilePath
byte[] byteArray = File.ReadAllBytes(filePath);
string hexString = getHexFromBytes(byteArray); // Google: bytes to hex
// Here is the meat...
if (hexString.Length > 0)
{
string sqlForOracle = "DECLARE buf BLOB; " +
"cBuf CLOB; " +
"BEGIN " +
"dbms_lob.createtemporary(buf, FALSE); " +
"dbms_lob.createtemporary(cBuf, FALSE); "; +
"dbms_lob.open(buf, dbms_lob.lob_readwrite); ";
int chunkSize = 32766;
if (hexString.Length > chunkSize)
{
sqlForOracle += "dbms_lob.open(cBuf, dbms_lob.lob_readwrite); ";
int startIdx = 0;
decimal hexChunks = decimal.Divide(hexString.Length / chunkSize);
for (int i = 0; i < hexChunks; i++)
{
int remainingHex = hexString.Length - (i * chunkSize);
if (remainingHex > chunkSize)
sqlForOracle += "dbms_lob.append(cBuf, '" + hexString.Substring(startIdx, chunkSize + "'); ";
else
sqlForOracle += "dbms_lob.append(cBuf, '" + hexString.Substring(startIdx, remainingHex) + "'); ";
startIdx = startIdx + chunkSize;
}
sqlForOracle += "dbms_lob.close(cBuf); ";
// Now we append the CLOB to the BLOB
sqlForOracle += "dbms_lob.append(buf, HEXTORAW(cBuf)); ";
}
else // write it straight to BLOB as we are below our chunk limit
sqlForOracle += "dbms_lob.append(buf, HEXTORAW('" + hexString + "')); ";
sqlForOracle += "dbms_lob.close(buf); ";
sqlForOracle += "UPDATE MyTable SET blobDate = buf WHERE ID = 123; END;";
}
sqlForOracle
позже записывается в файл с использованием FileStream
и StreamWriter
, и служба видит, существует ли файл, считывает его и обновляет с его помощью Oracle.
ОБНОВЛЕНИЯ
Ответ Мика на самом деле хорош, как есть, если вы используете четное число со своими фрагментами, поэтому мой на самом деле излишне вводит дополнительный шаг, если вам не нужно использовать фрагменты с нечетными номерами. Файл большего размера (однако он должен был бы конкурировать с вашей оперативной памятью) поэтому излишне повлиял бы на производительность, поскольку он также дважды записывается в память (CLOB, затем BLOB) перед преобразованием, так что будьте внимательны, но я хотел показать в С#, как фрагменты будут разбиты и как SQL будет фактически написан программно. Если вы хотите использовать только buf
, просто замените все переменные cBuf
на buf
, за исключением того, что вам нужен только один оператор dbms_lob.createtemporary()
и, очевидно, только один набор тегов .open()
и .close()
.
Итак, про эти теги я тоже читал форум AskTom на Oracle.com, где говорится, что добавление dbms_lob.open()
и .close()
к вашему лобовому объекту является необязательным, но более полезным для производительности при работе с числом добавлений > 2000 (или 2000 * 32766 = 65,532 МБ), где для завершения требуется почти вдвое больше времени (178,19%), и от этого становится только хуже: конечно, это зависит от размеров обрабатываемых файлов, действительно ли это полезно для вас или нет. Я добавил их выше.
person
vapcguy
schedule
10.12.2016
RAW(4000)
(или меньше), а не BLOB. - person Justin Cave   schedule 08.08.2013