Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, William.

Asked: February 04, 2003 - 1:33 pm UTC

Last updated: November 23, 2009 - 6:28 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

I have a need to know if a file which is defined in the database as a varchar2, i.e. imagefile varchar2(255), actually exists on the server or not. I read the answer where it was suggested to use the dbms_lob.fileexists function, however after reading the 8i Application Developer's Guide Large Objects and trying everything in there, I can not get the varchar2 variable successfully translated to the BFILE character type. I would have thought that the following would have been successful:

image_dir varchar2(255);
image_fn varchar2(255);
image_fileb BFILE;
.
.
image_dir := substr(image_file,1,instr(image_file,'/',-1));
image_fn := substr(image_file,1,instr(image_file,'/',-1)+1);
image_fileb := BFILENAME(image_dir, image_fn);
IF (dbms_lob.fileexists(image_fileb)) THEN

However, I receive the error: 'PLS-00382: expression is of wrong type'
I checked and the values of image_dir and image_fn are correct.
Your assistance will be greatly appreciated.

and Tom said...

Your error is because fileexists returns a NUMBER, not boolean (don't ask me why). But anyway..

BFILES work with directory objects. If you want to do it by "file path" and "file name", that'll not work as you have it coded. Consider:


ops$tkyte@ORA920> declare
2 l_bfile bfile := bfilename( '/tmp/', 'foo.dat' );
3 begin
4 if ( dbms_lob.fileexists( l_bfile ) = 1 )
5 then
6 dbms_output.put_line( 'Yes' );
7 else
8 dbms_output.put_line( 'No' );
9 end if;
10 end;
11 /
declare
*
ERROR at line 1:
ORA-22285: non-existent directory or file for FILEEXISTS operation
ORA-06512: at "SYS.DBMS_LOB", line 485
ORA-06512: at line 4


ops$tkyte@ORA920> create or replace directory MY_DIR as '/tmp'
2 /

Directory created.

ops$tkyte@ORA920>
ops$tkyte@ORA920> declare
2 l_bfile bfile := bfilename( 'MY_DIR', 'foo.dat' );
3 begin
4 if ( dbms_lob.fileexists( l_bfile ) = 1 )
5 then
6 dbms_output.put_line( 'Yes' );
7 else
8 dbms_output.put_line( 'No' );
9 end if;
10 end;
11 /
Yes

PL/SQL procedure successfully completed.


Now, if you can create a directory object -- that would be easiest -- however we can use utl_file to achieve this in a fashion:

ops$tkyte@ORA920> create or replace function file_exists( p_fname in varchar2 ) return boolean
2 as
3 l_file utl_file.file_type;
4 begin
5 l_file :=
6 utl_file.fopen( substr( p_fname, 1, instr(p_fname,'/',-1) ),
7 substr( p_fname, instr( p_fname, '/', -1)+1 ), 'r' );
8
9 utl_file.fclose( l_file );
10 return TRUE;
11 exception
12 when utl_file.invalid_path then return FALSE;
13 when utl_file.invalid_operation then return FALSE;
14 end;
15 /

Function created.

ops$tkyte@ORA920>
ops$tkyte@ORA920>
ops$tkyte@ORA920> begin
2 if ( file_exists( '/tmp/foo.dat' ) )
3 then
4 dbms_output.put_line( 'Yes' );
5 else
6 dbms_output.put_line( 'No' );
7 end if;
8 end;
9 /
Yes

PL/SQL procedure successfully completed.

ops$tkyte@ORA920> begin
2 if ( file_exists( '/tmp/foo2.dat' ) )
3 then
4 dbms_output.put_line( 'Yes' );
5 else
6 dbms_output.put_line( 'No' );
7 end if;
8 end;
9 /
No

PL/SQL procedure successfully completed.


Rating

  (8 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Won't work for image/graphics file

Will Cook, February 04, 2003 - 4:59 pm UTC

I appreciate your quick response, however I had already experimented with the utl_file functions and they will not work for image/graphics files. I apologize for not being more explicit that my problem has to do with image/graphics files, other than having the variables named image_dir, image_fn, and image_fileb. My mental lapse. Since BFILES deal with large binary objects I was hoping that using them would solve my problem. However, I have hundreds of directories each containing thousands of files, so creating directory objects as outlined is probably not a feasible solution for me. Perhaps some future release could contain a simple file exists regardless of file type function which would accept data contained in tables which can be extracted and used for the directory and filename information.

Tom Kyte
February 04, 2003 - 7:41 pm UTC

they will check for "existence" which is what you asked for.

foo.dat -- it is binary data.

the fileExists I wrote -- tells me if it exists or not, problem solved.

utl_file cannot be used to read/write binary files (until 9iR2), but it certainly doesn't care if they are binary or not when opening them

My problem was different than what I thought

Will Cook, February 05, 2003 - 12:29 pm UTC

My actual problem was not that UTL_FILE.FOPEN wouldn't open and therefore check for the existence of a graphics file, the problem was, at least on my server, how Oracle wants the directory and filename to be presented. The following does not work:
utl_file.fopen( substr( p_fname, 1, instr(p_fname,'/',-1) ),
substr( p_fname, instr( p_fname, '/', -1)+1 ), 'r');
The result is the directory name = /directory/
while the file name = filename
Whereas this does work:
utl_file.fopen(substr(p_fname, 1, instr(p_fname,'/',-1)-1), substr(p_fname,instr(p_fname,1,instr(p_fname,'/',-1)) 'r');
The result is the directory name = /directory
while the file name = /filename
For some reason, at least running Oracle 8.1.7 on SUN 2.8, it makes a difference on which argument to UTL_FILE.FOPEN the slash between the directory name and filename is.

Tom Kyte
February 05, 2003 - 12:44 pm UTC


your directory must match the init.ora setting of utl_file_dir typically.

Manual needs modification

Will Cook, February 05, 2003 - 12:58 pm UTC

Ah ha! That makes perfect sense. Unfortunately then, the examples in the Oracle8i Supplied PL/SQL Packages Reference, which are:
UTL_FILE_DIR=/appl/gl/log
UTL_FILE_DIR=/appl/gl/out

perhaps should be modified and some better examples and explanations supplied.


vj, July 24, 2003 - 9:36 am UTC

In my previous application i used to
insert a data from the directory (CREATE OR REPLACE DIRECTORY images AS 'C:\';) to the BLOB column as well as retrieval...

i got a question ? this application is running on JSP,WEBSPHERE,ORACLE 9I DB...In one of the JSP page we have a scanning interface, which typically scan the signature from the physical application..We have to insert that into BLOB column in the DB..

How can i acheive it ? How do i insert it from JSP to DATABASE and retrieve the same..any help is highly appreciated..


Rgds


Tom Kyte
July 24, 2003 - 9:41 am UTC

check out the LOB documentation of which there is alot:

</code> http://docs.oracle.com/docs/cd/B10501_01/nav/docindex.htm#index-APP <code>

your jsp is probably running on server 1 and the db on server 2 -- you will not use dbms_lob.loadFromFile or a bfile as that would imply the file is on server 2 -- but it won't be.

So -- you'll be using a java stream to stream the data in.

What is the error

vikas sharma, October 15, 2003 - 8:11 pm UTC

Hi Tom,

I have written the following the code. I am not able find out where the problem is.


1 declare
2 l_blob blob := empty_blob;
3 l_bfile bfile := bfilename( 'MYDIR', 'mog.doc' );
4 begin
5 dbms_lob.createtemporary(l_blob,false);
6 if ( dbms_lob.fileexists( l_bfile ) = 1 )
7 then
8 dbms_output.put_line( 'Yes' );
9 dbms_lob.fileopen(l_bfile,dbms_lob.file_readonly);
10 dbms_lob.loadfromfile( l_blob, l_bfile ,
11 dbms_lob.getlength(l_bfile) );
12 dbms_lob.fileclose(l_bfile);
13 else
14 dbms_output.put_line( 'No' );
15 end if;
16* end;
miller@STDDEV> /
Yes
declare
*
ERROR at line 1:
ORA-22288: file or LOB operation FILEOPEN failed
ORA-06512: at "SYS.DBMS_LOB", line 504
ORA-06512: at line 9

I am not able to understand why file open is failing. when file exists is true.

I have check the security also. It is read,modify,delete to everyone.

Thanks

Vikas Sharma

Tom Kyte
October 16, 2003 - 10:25 am UTC

incomplete test case -- i cannot see the definition of MYDIR.  and remember the file MUST be on the DATABASE SERVER and if you are on windoze, it MUST be on a local disk -- not a share (for you have to jump through massive hoops to make a share accessible to a background process like a database)

This is executed on the database server itself (so I know that /tmp/mog.doc exists)


ops$tkyte@ORA920> create or replace directory MYDIR as '/tmp/'
  2  /
 
Directory created.
 
ops$tkyte@ORA920>
ops$tkyte@ORA920> !echo 'Hello World' > /tmp/mog.doc
 
ops$tkyte@ORA920>
ops$tkyte@ORA920> declare
  2  l_blob     blob := empty_blob;
  3  l_bfile bfile := bfilename( 'MYDIR', 'mog.doc' );
  4      begin
  5  dbms_lob.createtemporary(l_blob,false);
  6   if ( dbms_lob.fileexists( l_bfile ) = 1 )
  7              then
  8                      dbms_output.put_line( 'Yes' );
  9  dbms_lob.fileopen(l_bfile,dbms_lob.file_readonly);
 10  dbms_lob.loadfromfile( l_blob, l_bfile ,
 11                         dbms_lob.getlength(l_bfile) );
 12  dbms_lob.fileclose(l_bfile);
 13  else
 14                      dbms_output.put_line( 'No' );
 15              end if;
 16  end;
 17  /
Yes
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA920>
ops$tkyte@ORA920> !chmod a= /tmp/mog.doc
 
ops$tkyte@ORA920> !ls -l /tmp/mog.doc
----------    1 tkyte    tkyte          12 Oct 16 10:25 /tmp/mog.doc
 
ops$tkyte@ORA920>
ops$tkyte@ORA920> declare
  2  l_blob     blob := empty_blob;
  3  l_bfile bfile := bfilename( 'MYDIR', 'mog.doc' );
  4      begin
  5  dbms_lob.createtemporary(l_blob,false);
  6   if ( dbms_lob.fileexists( l_bfile ) = 1 )
  7              then
  8                      dbms_output.put_line( 'Yes' );
  9  dbms_lob.fileopen(l_bfile,dbms_lob.file_readonly);
 10  dbms_lob.loadfromfile( l_blob, l_bfile ,
 11                         dbms_lob.getlength(l_bfile) );
 12  dbms_lob.fileclose(l_bfile);
 13  else
 14                      dbms_output.put_line( 'No' );
 15              end if;
 16  end;
 17  /
Yes
declare
*
ERROR at line 1:
ORA-22288: file or LOB operation FILEOPEN failed
Permission denied
ORA-06512: at "SYS.DBMS_LOB", line 504
ORA-06512: at line 9


<b>so, you should be getting more info in there (like I did) but i think your file exists but is not truly accessible to the server process</b>

 

File open Error

Vikas Sharma, October 16, 2003 - 2:46 pm UTC

hi Tom,

Thanks for your reply. Sorry for not providing the complete test case.
Here is the complete test case.

miller@STDDEV> create or replace directory mydir as '\\mtldb\UTLFILE';
Directory created.


miller@STDDEV>
miller@STDDEV> declare
2 l_blob blob := empty_blob;
3 l_bfile bfile := bfilename( 'MYDIR', 'mog.doc' );
4 begin
5 dbms_lob.createtemporary(l_blob,false);
6 if ( dbms_lob.fileexists( l_bfile ) = 1 )
7 then
8 dbms_output.put_line( 'Yes' );
9 dbms_lob.fileopen(l_bfile,dbms_lob.file_readonly);
10 dbms_lob.loadfromfile( l_blob, l_bfile ,
11 dbms_lob.getlength(l_bfile) );
12 dbms_lob.fileclose(l_bfile);
13 else
14 dbms_output.put_line( 'No' );
15 end if;
16 end;
17 /
Yes
declare
*
ERROR at line 1:
ORA-22288: file or LOB operation FILEOPEN failed
ORA-06512: at "SYS.DBMS_LOB", line 504
ORA-06512: at line 9

***************************
But when i change the directory as following it works.

miller@STDDEV> create or replace directory mydir as 'h:\UTLFILE';

Directory created.

miller@STDDEV> declare
2 l_blob blob := empty_blob;
3 l_bfile bfile := bfilename( 'MYDIR', 'mog.doc' );
4 begin
5 dbms_lob.createtemporary(l_blob,false);
6 if ( dbms_lob.fileexists( l_bfile ) = 1 )
7 then
8 dbms_output.put_line( 'Yes' );
9 dbms_lob.fileopen(l_bfile,dbms_lob.file_readonly);
10 dbms_lob.loadfromfile( l_blob, l_bfile ,
11 dbms_lob.getlength(l_bfile) );
12 dbms_lob.fileclose(l_bfile);
13 else
14 dbms_output.put_line( 'No' );
15 end if;
16 end;
17 /
Yes

PL/SQL procedure successfully completed.

miller@STDDEV>

I can understand that the UTLFILE folder shared. but it is not mapped dirve on server. It is on the local hard drive H:\ on windows.

Does bfile directory does not work with the UNC path?

And the other issue is if the server is able to see it as the output of file exists is "YES" then WHY it is not able to OPEN load it? Is it a bug?

I did not change any security,access permissions and it worked with h:\utlfile.

Thanks,
Regards

Vikas Sharma







Tom Kyte
October 16, 2003 - 5:32 pm UTC


no ideas for you as I cannot test using proprietary windoze techniques. I have no machines that run that OS. Sorry.

You'll have to contact support and work it that way -- sorry.

Thanks

Vikas Sharma, October 16, 2003 - 8:25 pm UTC

Hi Tom,

Thanks,

Vikas Sharma

dir exists

A reader, November 23, 2009 - 5:14 pm UTC

Tom:

Would this function work to check if a directory mount (MY_DIR) between one server (mount server) and oracle server exist?
just setup a small dummy file and schedule a job to check if file exists or not. or is it better to do something in java (java stored procedure)?

ops$tkyte@ORA920> declare
2 l_bfile bfile := bfilename( 'MY_DIR', 'foo.dat' );
3 begin
4 if ( dbms_lob.fileexists( l_bfile ) = 1 )
5 then
6 dbms_output.put_line( 'Yes' );
7 else
8 dbms_output.put_line( 'No' );
9 end if;
10 end;
11 /

Tom Kyte
November 23, 2009 - 6:28 pm UTC

that would work if the file was there

or utl_file.fopen could work as well, open the file for read

or utl_file.fopen in write mode (to create a test file, that'll see if the directory exists, you'd have to use a file name that was OK to overwrite)

or a java stored procedure

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here