在 BLOB for Work 或 Excel 文件中查找并替换字符串

Find and replace string inside BLOB for Work or Excel File

我需要查找和替换数据库中存储的数千个文档中过时的超链接。

目前我有一些函数可以将 BLOB 转换为 CLOB,执行查找和替换,然后再转换回 BLOB。

然而,最终结果并没有使文件保持原始状态,例如我存储了一个 word 文档,我找到超链接 www.google.co.uk 并替换,BLOB 数据不再是 word 文档类型,我无法打开它。

是否有推荐的方法来完成上述操作。

非常感谢,

Microsoft Word 和 Excel 文件不是文本文件,您只能替换其中的文本,并且绝对不能与 BLOB 一起使用。 docxxlsx 文件实际上是包含 XML 定义的 zip 文件(尝试更改文件扩展名并解压缩以查看)的文件。所以你需要:

  1. 解压缩文件
  2. 将需要更改的文件从 BLOB 转换为 CLOB
  3. 修改适当的 XML 文件的内容
  4. 将文件从 CLOB
  5. 转换回 BLOB
  6. 将修改后的文件添加回 zip 文件

我编写了下面的代码作为示例,说明如何替换 docx 文件。对于 xlsx 文件,每个 Excel sheet 都包含在不同的 XML 文件中,因此您需要稍微修改代码才能使其正常工作两种文件类型。

该代码确实使用了 APEX_ZIP 包,它极大地简化了对 zip 文件的处理,并且还使示例代码对于正在发生的事情更加清晰。如果您没有安装 APEX,您将需要弄清楚如何使用您拥有的 Oracle 包对文件进行 unzipping/rezipping。

DECLARE
    l_old_file       BLOB;
    l_new_file       BLOB;
    l_files          apex_zip.t_files;
    l_document       BLOB;
    l_clob           CLOB;
    l_dest_offsset   INTEGER;
    l_src_offsset    INTEGER;
    l_lang_context   INTEGER := DBMS_LOB.default_lang_ctx;
    l_warning        INTEGER;
BEGIN
    -- Get the blob you want to "correct"
    SELECT blob_content
      INTO l_old_file
      FROM apex_application_temp_files
     WHERE ROWNUM = 1;

    -- Get a list of all the file names contained within the zip
    l_files := apex_zip.get_files (l_old_file);

    -- Loop through all the files adding each one to the new zip
    FOR i IN l_files.FIRST .. l_files.LAST
    LOOP
        l_document := apex_zip.get_file_content (l_old_file, l_files (i));

        IF l_files (i) = 'word/document.xml'
        THEN
            -- if the file name is word/document.xml then make the changes to it
            
            DBMS_LOB.createTemporary (lob_loc => l_clob, cache => FALSE);

            l_dest_offsset := 1;
            l_src_offsset := 1;

            DBMS_LOB.converttoclob (dest_lob       => l_clob,
                                    src_blob       => l_document,
                                    amount         => DBMS_LOB.lobmaxsize,
                                    dest_offset    => l_dest_offsset,
                                    src_offset     => l_src_offsset,
                                    blob_csid      => DBMS_LOB.default_csid,
                                    lang_context   => l_lang_context,
                                    warning        => l_warning);

            --------------------
            -- This is where you would do any replacements
            --------------------
            l_clob := REPLACE (l_clob, 'www.google.co.uk', 'www.google.com');
            --------------------

            l_dest_offsset := 1;
            l_src_offsset := 1;

            DBMS_LOB.CONVERTTOBLOB (dest_lob       => l_document,
                                    src_clob       => l_clob,
                                    amount         => DBMS_LOB.lobmaxsize,
                                    dest_offset    => l_dest_offsset,
                                    src_offset     => l_src_offsset,
                                    blob_csid      => DBMS_LOB.default_csid,
                                    lang_context   => l_lang_context,
                                    warning        => l_warning);
        END IF;

        apex_zip.add_file (l_new_file, l_files (i), l_document);
    END LOOP;

    apex_zip.finish (l_new_file);
    --Do whatever you want with the "new" file here
END;