4.3 BFILE APIs
This section discusses the different operations supported through BFILE
s.
BFILE
variable either by using the BFILENAME
function or an equivalent API, or by using a SELECT
operation on a BFILE column, you can perform read operations on the BFILE
using APIs such as DBMS_LOB
. Note that BFILE
is a read-only data type. So, you cannot update or delete the operating system files, accessed using BFILE
s, through the BFILE
APIs.
The operations performed on BFILE
s are divided into following categories:
Table 4-1 Operations on BFILEs
Category | Operation | Example function /procedure in DBMS_LOB package
|
---|---|---|
Sanity Checking | Check if the BFILE exists on the server
|
FILEEXISITS |
Get the DIRECTORY object name and file name
|
FILEGETNAME |
|
Set the name of a BFILE in a locator without checking if the directory or file exists
|
BFILENAME |
|
Open / Close | Open a file | OPEN |
Check if the file was opened using the input BFILE locators
|
ISOPEN |
|
Close the file | CLOSE |
|
Close all previously opened files | FILECLOSEALL |
|
Read Operations | Get the length of the BFILE |
GETLENGTH |
Read data from the BFILE starting at the specified offset
|
READ |
|
Return part of the BFILE value starting at the specified offset using SUBSTR |
SUBSTR |
|
Return the matching position of a pattern in a BFILE using INSTR |
INSTR |
|
Operations involving multiple locators | Assign BFILE locator src to BFILE locator dst |
dst := src |
Load BFILE data into a LOB
|
LOADCLOBFROMFILE, LOADBLOBFROMFILE |
|
Compare all or part of the value of two BFILE s
|
COMPARE |
4.3.1 Sanity Checking
Sanity Checking functions on BFILEs enable you to retrieve information about the BFILEs.
Recall that the BFILENAME()
and OCILobFileSetName()
functions do not verify that the directory and path name you specify actually exist.
You can use the sanity checking functions to verify that a BFILE
exists and to extract the directory and file names from a BFILE
locator.
4.3.2 Opening and Closing a BFILE
You must OPEN
a BFILE
before performing any operations on it, and CLOSE
it before you terminate your program.
A BFILE
locator operates like a file
descriptor available as part of the standard input/output library of
most conventional programming languages. This implies that once you
define and initialize a BFILE
locator, and open the
file pointed to by this locator, all subsequent operations until the
closure of the file must be done from within the same program block
using the locator or local copies of it. The BFILE
locator variable can be used as a parameter to other procedures,
member methods, or external function callouts. However, it is
recommended that you open and close a file from the same program
block at the same nesting level.
You must close all the open BFILE
instances even in cases, where an exception or unexpected termination of your application occurs. In these cases, if a BFILE
instance is not closed, then it is still considered open by the database. Ensure that your exception handling strategy does not allow BFILE
instances to remain open in these situations.
You can close all open BFILE
s together by
using a procedure like DBMS_LOB.FILECLOSEALL
or
OCILobFileCloseAll()
.
4.3.3 Reading from a BFILE
You can perform many different read operations on the BFILE
data, including reading its length, reading part of the data, or reading the whole data.
When reading from a large BFILE
, you can use the streaming read mode in JDBC or OCI. In JDBC, you can achieve this by using the getBinaryStream()
method. In OCI, you can achieve it in the way as described in the following section.
Streaming Read in OCI
The most efficient way to read large amounts of BFILE
data is by using the OCILobRead2()
function with the streaming mechanism enabled, and using polling or callback. To do so, specify the starting point of the read using the offset
parameter as follows:
ub8 char_amt = 0;
ub8 byte_amt = 0;
ub4 offset = 1000;
OCILobRead2(svchp, errhp, locp, &byte_amt, &char_amt, offset, bufp, bufl,
OCI_ONE_PIECE, 0, 0, 0, 0);
When using polling mode, be sure to look at the value of the byte_amt
parameter after each OCILobRead2()
call to see how many bytes were read into the buffer, because the buffer may not be entirely full.
When using callbacks, the lenp
parameter, which is input to the callback, indicates how many bytes are filled in the buffer. Be sure to check the lenp
parameter during your callback processing because the entire buffer may not be filled with data.
Amount Parameter
- When calling the
DBMS_LOB.READ
API, the size of theamount
parameter can be larger than the size of the data. However, this parameter should be less than or equal to the size of the buffer. In PL/SQL, the buffer size is limited to 32K. - When calling the
OCILobRead2()
function, you can pass a value ofUB8MAXVAL
for thebyte_amt
parameter to read to the end of theBFILE
.
4.3.4 Working with Multiple BFILE Locators
Some BFILE
operations accept two locators, at least one of
which is a BFILE
locator. For the assignment and the comparison operations
involving BFILES, both the locators must be of BFILE
type.
Loading a LOB with BFILE
data involves special considerations that we
will discuss in the following sections:
Loading a LOB with BFILE Data
In PLSQL, the DBMS_LOB.LOADFROMFILE
procedure is deprecated in favor
of DBMS_LOB.LOADBLOBFROMFILE
and
DBMS_LOB.LOADCLOBFROMFILE
. Specifically, when you use
DBMS_LOB.LOADCLOBFROMFILE
procedure to load a
CLOB
or NCLOB
instance, it will perform the
character set conversions.
Specifying the Amount of BFILE Data to Load
The value you pass for the amount parameter to functions listed in the table below must be one of the following:
- An amount less than or equal to the actual size (in bytes) of the
BFILE
you are loading. - The maximum allowable LOB size (in bytes). Passing this value, loads the entire
BFILE
. You can use this technique to load the entireBFILE
without determining the size of theBFILE
before loading. To get the maximum allowable LOB size, use the technique described in the following table:
Table 4-2 Maximum LOB Size for Load from File Operations
Environment | Function | To pass maximum LOB size, get value of: |
---|---|---|
DBMS_LOB |
DBMS_LOB.LOADBLOBFROMFILE |
DBMS_LOB.LOBMAXSIZE |
DBMS_LOB |
DBMS_LOB.LOADCLOBFROMFILE |
DBMS_LOB.LOBMAXSIZE |
OCI |
OCILobLoadFromFile2() |
UB8MAXVAL |
OCI |
OCILobLoadFromFile() (For LOBs less than 4
gigabytes in size.)
|
UB4MAXVAL |
Loading a BLOB with BFILE Data
The DBMS_LOB.LOADBLOBFROMFILE
procedure loads a BLOB
with data from a BFILE
. It can be used to load data into any persistent or temporary BLOB
instance. This procedure returns the new source and the destination offsets of the BLOB, which you can then pass into subsequent calls, when used in a loop.
Loading a CLOB with BFILE Data
The DBMS_LOB.LOADCLOBFROMFILE
procedure loads a CLOB
or NCLOB
with character data from a BFILE
. It can be used to load data into a persistent or temporary CLOB
or NCLOB
instance. You can specify the character set ID of the BFILE
when calling this procedure and ensure that the character set is properly converted from the BFILE
data character set to the destination CLOB
or NCLOB
character set. This procedure returns the new source and destination offsets of the CLOB or NCLOB, which you can then passe into subsequent calls, when used in a loop.
- How to use
default csid(0)
. - How to load the entire file without calling
getlength
for theBFILE
. - How to find out the actual amount loaded using return offsets.
This example assumes that ad_source
is a BFILE
in
UTF8
character set format and the database character set is
UTF8
.
CREATE OR REPLACE PROCEDURE loadCLOB1_proc (dst_loc IN OUT CLOB) IS
src_loc BFILE := BFILENAME('MEDIA_DIR','monitor_3060.txt') ;
amt NUMBER := DBMS_LOB.LOBMAXSIZE;
src_offset NUMBER := 1 ;
dst_offset NUMBER := 1 ;
lang_ctx NUMBER := DBMS_LOB.DEFAULT_LANG_CTX;
warning NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE('------------ LOB LOADCLOBFORMFILE EXAMPLE ------------');
DBMS_LOB.FILEOPEN(src_loc, DBMS_LOB.FILE_READONLY);
/* The default_csid can be used when the BFILE encoding is in the same charset
* as the destination CLOB/NCLOB charset
*/
DBMS_LOB.LOADCLOBFROMFILE(dst_loc,src_loc, amt, dst_offset, src_offset,
DBMS_LOB.DEFAULT_CSID, lang_ctx,warning) ;
DBMS_OUTPUT.PUT_LINE(' Amount specified ' || amt ) ;
DBMS_OUTPUT.PUT_LINE(' Number of bytes read from source: ' || (src_offset-1));
DBMS_OUTPUT.PUT_LINE(' Number of characters written to destination: ' ||(dst_offset-1) );
IF (warning = DBMS_LOB.WARN_INCONVERTIBLE_CHAR)
THEN
DBMS_OUTPUT.PUT_LINE('Warning: Inconvertible character');
END IF;
DBMS_LOB.FILECLOSEALL() ;
END;
/
- How to get the character set ID from the character set name using the
NLS_CHARSET_ID
function. - How to load a stream of data from a single
BFILE
into different LOBs using the returned offset value and the language contextlang_ctx
. - How to read a warning message
This example assumes that ad_file_ext_01
is a BFILE
in JA16TSTSET
format and the database national character set is
AL16UTF16
.
CREATE OR REPLACE PROCEDURE loadCLOB2_proc (dst_loc1 IN OUT NCLOB,dst_loc2 IN OUT NCLOB) IS
src_loc BFILE := BFILENAME('MEDIA_DIR','monitor_3060.txt');
amt NUMBER := 100;
src_offset NUMBER := 1;
dst_offset NUMBER := 1;
src_osin NUMBER;
cs_id NUMBER := NLS_CHARSET_ID('JA16TSTSET'); /* 998 */
lang_ctx NUMBER := dbms_lob.default_lang_ctx;
warning NUMBER;
BEGIN
DBMS_OUTPUT.PUT_LINE('------------ LOB LOADCLOBFORMFILE EXAMPLE ------------');
DBMS_LOB.FILEOPEN(src_loc, DBMS_LOB.FILE_READONLY);
DBMS_OUTPUT.PUT_LINE(' BFILE csid is ' || cs_id) ;
/* Load the first 1KB of the BFILE into dst_loc1 */
DBMS_OUTPUT.PUT_LINE(' ----------------------------' ) ;
DBMS_OUTPUT.PUT_LINE(' First load ' ) ;
DBMS_OUTPUT.PUT_LINE(' ----------------------------' ) ;
DBMS_LOB.LOADCLOBFROMFILE(dst_loc1, src_loc, amt, dst_offset, src_offset,
cs_id, lang_ctx, warning);
/* the number bytes read may or may not be 1k */
DBMS_OUTPUT.PUT_LINE(' Amount specified ' || amt ) ;
DBMS_OUTPUT.PUT_LINE(' Number of bytes read from source: ' ||
(src_offset-1));
DBMS_OUTPUT.PUT_LINE(' Number of characters written to destination: ' ||
(dst_offset-1) );
if (warning = dbms_lob.warn_inconvertible_char)
then
DBMS_OUTPUT.PUT_LINE('Warning: Inconvertible character');
end if;
/* load the next 1KB of the BFILE into the dst_loc2 */
DBMS_OUTPUT.PUT_LINE(' ----------------------------' ) ;
DBMS_OUTPUT.PUT_LINE(' Second load ' ) ;
DBMS_OUTPUT.PUT_LINE(' ----------------------------' ) ;
/* Notice we are using the src_offset and lang_ctx returned from the previous
* load. We do not use value 1001 as the src_offset here because sometimes the
* actual amount read may not be the same as the amount specified.
*/
src_osin := src_offset;
dst_offset := 1;
DBMS_LOB.LOADCLOBFROMFILE(dst_loc2, src_loc, amt, dst_offset, src_offset,
cs_id, lang_ctx, warning);
DBMS_OUTPUT.PUT_LINE(' Number of bytes read from source: ' ||
(src_offset-src_osin) );
DBMS_OUTPUT.PUT_LINE(' Number of characters written to destination: ' ||
(dst_offset-1) );
if (warning = DBMS_LOB.WARN_INCONVERTIBLE_CHAR)
then
DBMS_OUTPUT.PUT_LINE('Warning: Inconvertible character');
end if;
DBMS_LOB.FILECLOSEALL() ;
END;
/