在 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
一起使用。 docx 和 xlsx 文件实际上是包含 XML 定义的 zip 文件(尝试更改文件扩展名并解压缩以查看)的文件。所以你需要:
- 解压缩文件
- 将需要更改的文件从
BLOB
转换为 CLOB
- 修改适当的 XML 文件的内容
- 将文件从
CLOB
转换回 BLOB
- 将修改后的文件添加回 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;
我需要查找和替换数据库中存储的数千个文档中过时的超链接。
目前我有一些函数可以将 BLOB 转换为 CLOB,执行查找和替换,然后再转换回 BLOB。
然而,最终结果并没有使文件保持原始状态,例如我存储了一个 word 文档,我找到超链接 www.google.co.uk 并替换,BLOB 数据不再是 word 文档类型,我无法打开它。
是否有推荐的方法来完成上述操作。
非常感谢,
Microsoft Word 和 Excel 文件不是文本文件,您只能替换其中的文本,并且绝对不能与 BLOB
一起使用。 docx 和 xlsx 文件实际上是包含 XML 定义的 zip 文件(尝试更改文件扩展名并解压缩以查看)的文件。所以你需要:
- 解压缩文件
- 将需要更改的文件从
BLOB
转换为CLOB
- 修改适当的 XML 文件的内容
- 将文件从
CLOB
转换回 - 将修改后的文件添加回 zip 文件
BLOB
我编写了下面的代码作为示例,说明如何替换 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;