如何解决 Oracle DBMS_LOB 的问题
How to solved problem with Oracle DBMS_LOB
我正在尝试将 XML 文件的信息保存在数据库 table 中,我正在使用此过程:
create or replace PROCEDURE P_FILEUPLOAD_XML (P_CMTT_CODE IN NUMBER DEFAULT 15, P_TEXT IN VARCHAR2, P_TEXT_NAR IN VARCHAR2, P_PATH IN VARCHAR2, P_FILENAME IN VARCHAR2, P_RET_VAL OUT NUMBER) IS
GRUPO VARCHAR2(20);
l_dir CONSTANT VARCHAR2(35) := P_PATH;
l_fil CONSTANT VARCHAR2(30) := P_FILENAME;
l_loc BFILE; -- Pointer to the BFILE
l_ret BOOLEAN := FALSE; -- Return value
l_pos NUMBER := 1; -- Current position in the file (file begins at position 1)
l_sum number default 8000; -- Amount of characters have been read
l_buf VARCHAR2(32767); -- Read Buffer
l_sen CONSTANT RAW(100) := UTL_RAW.CAST_TO_RAW(CHR(10)); -- Character at the end of the file is NEWLINE (ascii = 10)
l_end NUMBER; -- End of the current word which will be read
l_counter NUMBER := 0; -- Counter for line sequence
l_line VARCHAR2(32767); -- Contains the info line by line for insert
BEGIN
SELECT TEXTO INTO GRUPO FROM gzvcatg
UNPIVOT ((codigo, texto) FOR gzvcatg_external_code IN (
(gzvcatg_external_code1, gzvcatg_desc1) AS '1')
WHERE GZVCATG_GROUP = 'TIT_ELEC'
AND CODIGO = 'PATH';
-- Mapping the physical file with the pointer to the BFILE
l_loc := BFILENAME(GRUPO,'ES0000251446027471.xml');
-- Open the file in READ_ONLY mode
DBMS_LOB.OPEN(l_loc,DBMS_LOB.LOB_READONLY);
LOOP
l_counter := l_counter + 1; -- Counter for sequence
-- Calculate the end of the current word
l_end := DBMS_LOB.INSTR(l_loc,l_sen,l_pos,1);
-- Process end-of-file
IF (l_end = 0) THEN
l_end := DBMS_LOB.INSTR(l_loc,l_sen,l_pos,1);
l_sum := l_end - l_pos - 1;
EXIT;
END IF;
-- Read until end-of-file
l_sum := l_end - l_pos;
DBMS_LOB.READ(l_loc,l_sum,l_pos,l_buf);
l_line := UTL_RAW.CAST_TO_VARCHAR2(l_buf);
BEGIN
INSERT INTO SPRCMNT (
SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR)
VALUES(P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR);
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
END;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
DBMS_LOB.CLOSE(l_loc);
P_RET_VAL := 3;
dbms_output.put_line('P_RET_VAL:' || P_RET_VAL);
END;
但是当我执行该过程时,出现以下错误:
Error:ORA-22285: non-existent directory or file FILEOPEN operation
我不明白如果我的 XML 文件存在,为什么路径 C:\XMLS\
存在。
我得到了带有查询结果的路线。
这个Query的结果被分配给了一个叫做GRUPO
的变量,这是我在程序开始时声明的,然后我把这个变量作为参数放在函数BFILENAME
,它最初包含 directory
y filename
。您可以查看文档 BFILENAME
here
l_loc := BFILENAME(GRUPO,'ES0000251446027471.xml');
除此之外我在Oracle中创建了一个目录如下:
CREATE OR REPLACE DIRECTORY DIR_XML as 'C:\XMLS\';
我也给了目录权限
GRANT ALL ON DIRECTORY DIR_XML TO PUBLIC;
我在这个问题上浪费了很多时间,但我找不到任何解决方案。任何帮助将不胜感激。
Error:ORA-22285: non-existent directory or file for fileopen operation
我不明白为什么路径 C:\XMLS\ 确实存在,如果我的 XML 文件存在。
原因是 XML 文件存在于您的本地硬盘上,但 PL/SQL 在数据库服务器上运行。如果要通过 DBMS_LOB
.
访问文件,则需要将文件放在数据库服务器上
来自the documentation you linked to:
- 'directory' is a database object that serves as an alias for a full path name on the server file system where the files are actually located.
所以 GRUPO
的计算结果应该是 'DIR_XML'
而不是 'C:\XMLS'
。该文档中的示例显示了这一点。 (有一个基于存储为数据库参数的路径的旧目录前对象机制,但不太安全...)
如果你只有路径可以查找目录名:
select directory_name from all_directories where directory_path = 'C:\XMLS'
请记住,目录路径不必是唯一的,因此您可能需要处理重复项。
但正如@Matthew 已经解释过的那样,as the documentation says(强调):
A directory object specifies an alias for a directory on the server file system where ...
数据库只能查看其自身文件系统(本地或共享)上的文件,而不能查看客户端文件系统上的文件。如果您也是 运行 本地数据库,则没有区别(尽管目录和文件权限仍然很重要)。如果您正在访问远程数据库,那么它无法看到您的客户端 C: 驱动器,如果您提供目录对象名称,您仍然会得到类似:
ORA-22288: file or LOB operation FILEOPEN failed
No such file or directory
您必须将 XML 文件放在操作系统帐户有权访问的数据库服务器上的目录中,并创建一个指向服务器上该位置的目录对象;然后引用目录对象名称,而不是底层文件系统路径。
尝试以下操作:
- 将 DIR_XML 文件夹设置为共享文件夹,每个人都具有 read/write 权限
- 使用目录路径 '\\192.168.2.100\dir_xml' 而不是 'C:\DIR_XML'
将192.168.2.100替换为C:\DIR_XML所在的IP地址或机器名
不要使用 c:\ 路径。使用网络 path.Make 确保 \123.3.3.3\xml\ 文件夹可以从您的 sql 客户端机器和 Oracle 服务器访问。如果您检查 Ora tnsnames.ora 文件,您可以找到您的数据库服务器名称。
检查服务器创建一个共享文件夹,然后使用它。
192.168.1.0\xml\
Tnsnames.ora 例子
ORA11 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.0)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = ORA12)
)
)
我正在尝试将 XML 文件的信息保存在数据库 table 中,我正在使用此过程:
create or replace PROCEDURE P_FILEUPLOAD_XML (P_CMTT_CODE IN NUMBER DEFAULT 15, P_TEXT IN VARCHAR2, P_TEXT_NAR IN VARCHAR2, P_PATH IN VARCHAR2, P_FILENAME IN VARCHAR2, P_RET_VAL OUT NUMBER) IS
GRUPO VARCHAR2(20);
l_dir CONSTANT VARCHAR2(35) := P_PATH;
l_fil CONSTANT VARCHAR2(30) := P_FILENAME;
l_loc BFILE; -- Pointer to the BFILE
l_ret BOOLEAN := FALSE; -- Return value
l_pos NUMBER := 1; -- Current position in the file (file begins at position 1)
l_sum number default 8000; -- Amount of characters have been read
l_buf VARCHAR2(32767); -- Read Buffer
l_sen CONSTANT RAW(100) := UTL_RAW.CAST_TO_RAW(CHR(10)); -- Character at the end of the file is NEWLINE (ascii = 10)
l_end NUMBER; -- End of the current word which will be read
l_counter NUMBER := 0; -- Counter for line sequence
l_line VARCHAR2(32767); -- Contains the info line by line for insert
BEGIN
SELECT TEXTO INTO GRUPO FROM gzvcatg
UNPIVOT ((codigo, texto) FOR gzvcatg_external_code IN (
(gzvcatg_external_code1, gzvcatg_desc1) AS '1')
WHERE GZVCATG_GROUP = 'TIT_ELEC'
AND CODIGO = 'PATH';
-- Mapping the physical file with the pointer to the BFILE
l_loc := BFILENAME(GRUPO,'ES0000251446027471.xml');
-- Open the file in READ_ONLY mode
DBMS_LOB.OPEN(l_loc,DBMS_LOB.LOB_READONLY);
LOOP
l_counter := l_counter + 1; -- Counter for sequence
-- Calculate the end of the current word
l_end := DBMS_LOB.INSTR(l_loc,l_sen,l_pos,1);
-- Process end-of-file
IF (l_end = 0) THEN
l_end := DBMS_LOB.INSTR(l_loc,l_sen,l_pos,1);
l_sum := l_end - l_pos - 1;
EXIT;
END IF;
-- Read until end-of-file
l_sum := l_end - l_pos;
DBMS_LOB.READ(l_loc,l_sum,l_pos,l_buf);
l_line := UTL_RAW.CAST_TO_VARCHAR2(l_buf);
BEGIN
INSERT INTO SPRCMNT (
SPRCMNT_CMTT_CODE,
SPRCMNT_TEXT,
SPRCMNT_TEXT_NAR)
VALUES(P_CMTT_CODE,
P_TEXT,
P_TEXT_NAR);
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
END;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error:' || SQLERRM);
DBMS_LOB.CLOSE(l_loc);
P_RET_VAL := 3;
dbms_output.put_line('P_RET_VAL:' || P_RET_VAL);
END;
但是当我执行该过程时,出现以下错误:
Error:ORA-22285: non-existent directory or file FILEOPEN operation
我不明白如果我的 XML 文件存在,为什么路径 C:\XMLS\
存在。
我得到了带有查询结果的路线。
这个Query的结果被分配给了一个叫做GRUPO
的变量,这是我在程序开始时声明的,然后我把这个变量作为参数放在函数BFILENAME
,它最初包含 directory
y filename
。您可以查看文档 BFILENAME
here
l_loc := BFILENAME(GRUPO,'ES0000251446027471.xml');
除此之外我在Oracle中创建了一个目录如下:
CREATE OR REPLACE DIRECTORY DIR_XML as 'C:\XMLS\';
我也给了目录权限
GRANT ALL ON DIRECTORY DIR_XML TO PUBLIC;
我在这个问题上浪费了很多时间,但我找不到任何解决方案。任何帮助将不胜感激。
Error:ORA-22285: non-existent directory or file for fileopen operation
我不明白为什么路径 C:\XMLS\ 确实存在,如果我的 XML 文件存在。
原因是 XML 文件存在于您的本地硬盘上,但 PL/SQL 在数据库服务器上运行。如果要通过 DBMS_LOB
.
来自the documentation you linked to:
- 'directory' is a database object that serves as an alias for a full path name on the server file system where the files are actually located.
所以 GRUPO
的计算结果应该是 'DIR_XML'
而不是 'C:\XMLS'
。该文档中的示例显示了这一点。 (有一个基于存储为数据库参数的路径的旧目录前对象机制,但不太安全...)
如果你只有路径可以查找目录名:
select directory_name from all_directories where directory_path = 'C:\XMLS'
请记住,目录路径不必是唯一的,因此您可能需要处理重复项。
但正如@Matthew 已经解释过的那样,as the documentation says(强调):
A directory object specifies an alias for a directory on the server file system where ...
数据库只能查看其自身文件系统(本地或共享)上的文件,而不能查看客户端文件系统上的文件。如果您也是 运行 本地数据库,则没有区别(尽管目录和文件权限仍然很重要)。如果您正在访问远程数据库,那么它无法看到您的客户端 C: 驱动器,如果您提供目录对象名称,您仍然会得到类似:
ORA-22288: file or LOB operation FILEOPEN failed
No such file or directory
您必须将 XML 文件放在操作系统帐户有权访问的数据库服务器上的目录中,并创建一个指向服务器上该位置的目录对象;然后引用目录对象名称,而不是底层文件系统路径。
尝试以下操作:
- 将 DIR_XML 文件夹设置为共享文件夹,每个人都具有 read/write 权限
- 使用目录路径 '\\192.168.2.100\dir_xml' 而不是 'C:\DIR_XML'
将192.168.2.100替换为C:\DIR_XML所在的IP地址或机器名
不要使用 c:\ 路径。使用网络 path.Make 确保 \123.3.3.3\xml\ 文件夹可以从您的 sql 客户端机器和 Oracle 服务器访问。如果您检查 Ora tnsnames.ora 文件,您可以找到您的数据库服务器名称。 检查服务器创建一个共享文件夹,然后使用它。 192.168.1.0\xml\ Tnsnames.ora 例子
ORA11 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.0)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = ORA12)
)
)