Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Сохранить LOB на диске  [new]
Alex_Guest2
Guest
Подскажите, а можно ли средствами PL/SQL сохранить LOB в виде файла на диске? Или может быть как то иначе? Очень нужно.
29 янв 04, 13:22    [512697]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Евгений Гудзюк
Member

Откуда:
Сообщений: 224
Если размер данных в LOB < 32K то DBMS_LOB
29 янв 04, 13:30    [512717]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
По крайней мере в Oracle 9.2 пакет sys.UTL_FILE работает с файлами > 32K.

http://asktom.oracle.com/pls/ask/f?p=4950:8:11626726705839348247::NO::F4950_P8_DISPLAYID,F4950_P8_CRITERIA:6379798216275,


Prior to Oracle9iR2 you will need to use Java, C, VB, some 3gl language.

In 9iR2 -- PLSQL can write binary files using UTL_FILE.

In 9iR1 and before, you will need to use Java or some other 3gl that has the
ability to do this.


create or replace directory TMP_FILE as '/tmp/file';

create global temporary table tmp_blob (b blob) on commit delete rows;

declare
  v_file_name varchar2(64) := 'cat.bmp';
  v_blob blob;
  in_file bfile;
  out_file utl_file.file_type;
  v_buffer raw (32767);
  v_amount binary_integer := 32767;
  v_pos integer := 1;
  v_blob_len integer;
begin
  insert into tmp_blob values (empty_blob()) return b into v_blob;

  -- Читаем файл.

  in_file := bfilename('TMP_FILE', v_file_name);
  dbms_lob.fileopen(in_file);
  dbms_lob.loadfromfile(v_blob, in_file, dbms_lob.getlength(in_file));
  dbms_lob.fileclose (in_file);
  dbms_output.put_line('lob length = '||dbms_lob.getlength (v_blob)||';');

  -- Пишем в новый файл

  out_file := utl_file.fopen ('TMP_FILE', 'new_'||v_file_name, 'w', 32760);
  v_blob_len := dbms_lob.getlength (v_blob);
  while v_pos < v_blob_len loop
    dbms_lob.read (v_blob, v_amount, v_pos, v_buffer);
    utl_file.put_raw (out_file, v_buffer, true);
    v_pos := v_pos + v_amount;
  end loop;
  utl_file.fclose(out_file);

  commit;
exception when others then
  if utl_file.is_open(out_file) then
    utl_file.fclose(out_file);
  end if;
  raise;
end;
/
29 янв 04, 15:44    [513065]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
v@d
Member

Откуда: Москва
Сообщений: 1118
to Denis Popov> Пасиб за хороший пример. Тока у меня инстанс встал с 600 ошибкой
29 янв 04, 17:03    [513228]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
А что в дампе? Если что - можно и через Java, в вышеприведенной ссылке есть пример кода.
29 янв 04, 17:21    [513259]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
v@d
Member

Откуда: Москва
Сообщений: 1118
alert.log
------------------------------------------------------------
Thu Jan 29 17:06:20 2004
Errors in file c:\oracle\admin\educ\udump\educ_ora_1748.trc:
ORA-00600: internal error code, arguments: [4427], [], [], [], [], [], [], []
ORA-00600: internal error code, arguments: [kcblibr_1], [4294967295], [2], [4199049], [128], [], [], []
------------------------------------------------------------
educ_pmon_600.trc
*** 2004-01-29 16:44:15.000
*** SESSION ID:(1.1) 2004-01-29 16:44:15.000
error 474 detected in background process
ORA-00474: SMON process terminated with error
------------------------------------------------------------
Будет повод поставить патч 9.2.0.4 Благо БД тестовая.
29 янв 04, 17:30    [513282]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
v@d
Member

Откуда: Москва
Сообщений: 1118
to Denis Popov> Какая-то бяда с этим примером, на выходе получается файл, отличающийся по размеру (чуть больше) :((
Пока не могу понять, что дописывается...
Вы не проверяли этот пример? У Вас все ОК?
2 фев 04, 00:18    [516304]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
Да, проверял, но, к сожалению, не обратил внимания на одну деталь: добавлялся лишний байт оказался конец файла, равный 0x0A. Проверка нескольких других файлов (bmp, gif, pdf, txt) дала тот же самый результат... пока не натолкнулся на jpg - в этом случае размер получившегося файла оказался меньше исходного, хотя и с тем же добавлением 0x0A в конце. Как это объяснить - не знаю, но что самое интересное - в любом случае все файлы нормально показывались в просмотре, даже jpg, поэтому казус с изменения размера я сразу и не заметил.
2 фев 04, 10:44    [516557]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
v@d
Member

Откуда: Москва
Сообщений: 1118
Я тестил на ехе-нике, после выгрузки он стал неработоспособный вот и обратил внимание на размер :((
Пойду Тома читать, хотя может быть кто нибудь уже сталкивался с этими граблями и знает в чем дело?
2 фев 04, 11:12    [516638]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
Вот как раз у Т.Кайта с этим все в порядке:) Если выгружать BLOB'ы через методы упомянутого java-класса, размер получившегося файла в точности совпадает с размером исходного, я проверил на bmp, jpeg, exe. Единственное - мне приходится дополнительно давать привелегию на запись в файл через

dbms_java.grant_permission(:username, 'SYS:java.io.FilePermission', :file_name, 'write');
2 фев 04, 11:55    [516751]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
v@d
Member

Откуда: Москва
Сообщений: 1118
to Denis Popov> Эхх, ну не знаю я жаву, а через dbms_lob, utl_file вроде так все хорошо и понятно было :)
2 фев 04, 12:20    [516806]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
v@d
Member

Откуда: Москва
Сообщений: 1118
Внесу свой посильный вклад в борьбу с BLOBA'ми :) (Большое спасибо Kovalchuk Vitaly V, Fedorchenko Aleksey, Denis Popov).
utl_file.put_raw() для записи файла к сожалению не подходит. см. здесь.
ЗЫ. Все это уже было по форуму, я лишь собрал все одном месте. Проверял на Winnt 2Y, 4 srvpack, ORACLE 9.2.0.1
/*##############################################################################*/
--1. Источник https://www.sql.ru/forum/actualthread.aspx?bid=3&tid=68630

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED saveblob
AS
import java.sql.*; 
import java.io.*; 
import oracle.jdbc.driver.*; 
import java.util.*; 
import oracle.sql.*; 

public class SaveBlob { 

public static void Save(String filename, int id) { 
Connection conn = null; 
OraclePreparedStatement stmt = null; 
InputStream infstrm = null; 
OutputStream outstrm = null; 
try { 
conn = new OracleDriver().defaultConnection(); 
stmt = (OraclePreparedStatement) conn.prepareStatement("select field_with_blob from tmp_blob where id=:1"); 
stmt.setInt(1,id); 
OracleResultSet rset = (OracleResultSet) stmt.executeQuery(); 
if (rset.next()) { 
oracle.sql.BLOB myblob = rset.getBLOB(1); 
byte[] buffer = new byte[myblob.getChunkSize()]; 
infstrm = myblob.getBinaryStream(); 
outstrm = new FileOutputStream(filename); 
int len; 
while((len = infstrm.read(buffer)) != -1){ 
outstrm.write(buffer, 0, len); 
} 
infstrm.close(); 
outstrm.close(); 
} 
stmt.close(); 
conn.close(); 
} catch (Exception e) { 
System.err.println(e.getMessage()); 
try { 
if (outstrm != null) outstrm.close(); 
} catch(Exception ex) {} 
try { 
if (infstrm != null) infstrm.close(); 
} catch(IOException ex) {} 
try { 
if (stmt != null) stmt.close(); 
} catch(SQLException ex) {} 
try { 
if (conn != null) conn.close(); 
} catch(SQLException ex) {} 
} 
} 
}
/*##############################################################################*/
--2. создаем процедуру для сохранения bloba в файл

CREATE OR REPLACE PROCEDURE SaveBlob (filename STRING, id NUMBER)
IS
   LANGUAGE JAVA
      NAME 'SaveBlob.Save(java.lang.String,int)';
/*##############################################################################*/
--3. создаем директорию, таблицу и последовательность

CREATE OR REPLACE DIRECTORY dir_tmp_file AS 'c:/tmp/';
CREATE TABLE tmp_blob (id NUMBER, field_with_blob BLOB);
CREATE SEQUENCE sq$tmp_blob$id START WITH 1;
/*##############################################################################*/
--4. создаем процедуру для загрузки файла в Blob

--Источник https://www.sql.ru/forum/actualthread.aspx?bid=3&tid=71323

CREATE OR REPLACE PROCEDURE LoadBlob (l_file_name VARCHAR2)
AS
   out_file      UTL_FILE.file_type;
   v_blob        BLOB;
   in_file       BFILE;
   v_file_name   VARCHAR2 (128);
BEGIN
   INSERT INTO tmp_blob
        VALUES (sq$tmp_blob$id.NEXTVAL, EMPTY_BLOB ())
     RETURN    field_with_blob
          INTO v_blob;

   v_file_name := l_file_name;
   in_file := BFILENAME ('DIR_TMP_FILE', v_file_name);
   DBMS_LOB.fileopen (in_file); --открыть файл на чтение

   DBMS_LOB.loadfromfile (v_blob, in_file, DBMS_LOB.getlength (in_file));
   DBMS_LOB.fileclose (in_file);
   DBMS_OUTPUT.put_line (
         'lob length = '
      || DBMS_LOB.getlength (v_blob)
      || ';'
   );
   COMMIT;
EXCEPTION
   WHEN OTHERS
   THEN
      IF UTL_FILE.is_open (out_file)
      THEN
         UTL_FILE.fclose (out_file);
      END IF;

      RAISE;
END;
/*##############################################################################*/
--5. Пример вызова

execute LoadBlob('test.mp3');
execute SaveBlob('c:/tmp/new_test.mp3',27); 
/*##############################################################################*/
3 фев 04, 00:19    [517976]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Denis Popov
Member

Откуда: Санкт-Петербург
Сообщений: 7862
ИМХО необязательно привязываться к тому, что данные LOB'а находятся в определенной таблице, а именно TMP_BLOB.FIELD_WITH_BLOB:) Опять же, все нижеследующее целиком следует отсюда:

create or replace and resolve java source named "LOBUtils" as
import oracle.sql.BLOB;
import oracle.sql.CLOB;
import java.io.*;
import java.sql.*;
public class LOBUtils {
  final static int bBufLen = 4 * 8192;

  public static long BLOB2File(BLOB BLOB, String outFile)
  throws IOException, SQLException {
    OutputStream out = new FileOutputStream(outFile);
    InputStream in = BLOB.getBinaryStream();
    int length = -1;
    long read = 0;
    byte[] buf = new byte[bBufLen];
    while ((length = in.read(buf)) != -1) {
      out.write(buf, 0, length);
      read += length;
    }
    in.close();
    out.close();
    return read;
  }

  public static long CLOB2File(CLOB clob, String outFile)
  throws IOException, SQLException {
    BufferedWriter out = new BufferedWriter(new FileWriter(outFile));
    BufferedReader in = new BufferedReader(new InputStreamReader(clob.getAsciiStream()));
    int length = -1;
    long read = 0;
    char[] buf = new char[bBufLen];
    while ((length = in.read(buf, 0, bBufLen)) != -1) {
      out.write(buf, 0, length);
      read += length;
    }
    in.close();
    out.close();
    return read;
  }
}
/

create or replace package lobutils as

function BLOB2File (
    p_BLOB BLOB
  , p_file_name varchar2
) return number as
    language java
    name 'LOBUtils.BLOB2File(oracle.sql.BLOB, java.lang.String) return long';

function CLOB2File (
    p_clob clob
  , p_file_name varchar2
) return number as
    language java
    name 'LOBUtils.CLOB2File(oracle.sql.CLOB, java.lang.String) return long';
end;
/

create or replace directory TMP_FILE as '/tmp/file';

create global temporary table tmp_blob (b blob) on commit delete rows;

declare
  v_blob blob;
  in_file bfile;
  n integer;
begin
  insert into tmp_blob values (empty_blob()) return b into v_blob;
  -- Читаем.

  in_file := bfilename('TMP_FILE', 'cat.bmp');
  dbms_lob.fileopen(in_file);
  dbms_lob.loadfromfile(v_blob, in_file, dbms_lob.getlength(in_file));
  dbms_lob.fileclose (in_file);
  -- Пишем.

  n := lobutils.BLOB2file(v_blob, '/tmp/file/new_cat.bmp');
exception when others then
  if dbms_lob.fileisopen(in_file) = 1 then
    dbms_lob.fileclose(in_file);
  end if;
  raise;
end;
/
Точно так же можно написать процедуры вроде File2BLOB, Flie2CLOB. ИМХО проблема может состоять в необходимости явного указания директории файла, а не через оракловый объект DIRECTORY.
3 фев 04, 10:36    [518227]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Viktor_Karasev
Guest
Подскажите пож-та как мне перед тем как записывать данные из файла в BLOB сначала запустить функцию - XXX (b in blob) return blob;
которой передать как раз то что есть в файле, а уже результат этой функции записать в таблицу?
15 дек 04, 14:31    [1182868]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: Сохранить LOB на диске  [new]
IgorD
Member

Откуда: Анадырь ;)
Сообщений: 276
нашел полный набор функций по чтению/записи в файл на Java тут
18 фев 15, 17:31    [17283260]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
Vint
Member

Откуда: Москва
Сообщений: 4564
IgorD,
ты форум сначала просматривал?)) не прошло и 11 лет..
18 фев 15, 17:53    [17283417]     Ответить | Цитировать Сообщить модератору
 Re: Сохранить LOB на диске  [new]
bishnike
Member

Откуда: ст.Зеленчукская
Сообщений: 372
Vint,

та может не заметил человек дату просто, мало ли как он наткнулся на этот топик.

Да и лишним не будет. Может кто-то спасется на этой ссылке :D
18 фев 15, 18:23    [17283550]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить