When i am searching for directories registered to UTL_DIR i am getting the following :
select value from v$parameter where name='utl_file_dir';
/usr/tmp, /usr/tmp, /oradata/hrtst/db/tech_st/11.2.0/appsutil/outbound/HRTS, /usr/tmp
Does this mean /usr/tmp is the directory for UTL_DIR ?
also i cannot search for /oradata/hrtst/db/tech_st/11.2.0/appsutil/outbound/HRTS through winscp or putty.
Also i created a directory like
create or replace directory MY_DIR as '/usr/tmp';
and then i tried to write in this folder :
DECLARE
fileHandler UTL_FILE.FILE_TYPE;
begin
fileHandler := UTL_FILE.FOPEN('MY_DIR', 'test_file.txt', 'W');
UTL_FILE.PUTF(fileHandler, 'Writing TO a file\n');
UTL_FILE.FCLOSE(fileHandler);
EXCEPTION
WHEN others THEN
raise_application_error(-20000, 'ERROR: Invalid PATH FOR file.');
END;
anonymous block completed
though this block got executed succesfuly but no file got created in the directory when i checked.
Related
I am trying to create directory is SQL Developer and create a simple text file there using this code :
CREATE DIRECTORY ABC AS '/abc';
DECLARE
fileHandler UTL_FILE.FILE_TYPE;
BEGIN
fileHandler := UTL_FILE.FOPEN('ABC', 'test_file.txt', 'W');
UTL_FILE.PUTF(fileHandler, 'Writing to a file\n');
UTL_FILE.FCLOSE(fileHandler);
END;
But it ends up with that Error
29283. 00000 - "invalid file operation"
*Cause: An attempt was made to read from a file or directory that does
not exist, or file or directory access was denied by the
operating system.
*Action: Verify file and directory access privileges on the file system,
and if reading, verify that the file exists.
In SQL developer the directory variable is created and visible
So, my question is Does that piece of code suppose to create directory by itself or do i have to create it manually? (I don't have access to the servers file system)
It looks like GRANTS are missing.
To create a directory:
CREATE OR REPLACE DIRECTORY alias AS 'pathname';
Where:
alias is the name of the directory alias.
pathname is the physical directory path.
To Grant:
GRANT permission ON DIRECTORY alias TO {user | role | PUBLIC};
Where:
permission is one of the following:
READ for read-only access
WRITE for write-only access
ALL for read and write access
alias is the name of the directory alias.
user is a database user name.
Edit:
Directory Check:
SQL> SELECT DIRECTORY_NAME , DIRECTORY_PATH FROM DBA_DIRECTORIES WHERE DIRECTORY_NAME = 'BDUMP';
DIRECTORY_NAME DIRECTORY_PATH
------------------------------ ---------------
BDUMP /home/fil_test/
Change directory permission. By default it has only Read and execute permission for others.
terminal$ chmod 777 fil_test
Block:
DECLARE
fHandle UTL_FILE.FILE_TYPE;
BEGIN
fHandle := UTL_FILE.FOPEN ('BDUMP', 'test_file', 'w');
UTL_FILE.PUT (fHandle, 'This is the first line');
UTL_FILE.PUT (fHandle, 'This is the second line');
UTL_FILE.PUT_LINE (fHandle, 'This is the third line');
UTL_FILE.FCLOSE (fHandle);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE (
'Exception: SQLCODE=' || SQLCODE || ' SQLERRM=' || SQLERRM);
RAISE;
END;
/
Execution:
SQL> #tt.sql
PL/SQL procedure successfully completed.
And i See the file created:
terminal$ ls -lrt test_file*
-rw-r----- 1 oracle dba 68 Oct 24 14:49 test_file
I create a log file in my procedure:
v_log_file VARCHAR2 (250) := FND_FILE.LOG;
and during my procedure I write in this file :
FND_FILE.PUT_LINE (
v_log_file,
'### start');
How can I see my log file to check if it's written correctly? Where can I find my log file?
You can use DBMS_OUTPUT.PUT_LINE instead to view it in SQL developer. Use the below code before compiling your anonymous block.
SET SERVEROUTPUT ON;
I am using util_file.fopen to import a .txt file into a database. However, I do not want hardcode the directory. Is there a way save the current directory to a variable or log the path? That way I can create an oracle directory that is the current directory, and util_file.fopen will always open the .txt file that is in the directory that I am running my pl/sql from
I know that "HOST CD" will show me my current directory, but I have not been able to save it to a variable or log it
Thanks
Create multiple directory objects:
CREATE DIRECTORY DIRECTORY_1 AS '/some/path';
CREATE DIRECTORY DIRECTORY_2 AS '/some/other/path';
CREATE DIRECTORY DIRECTORY_3 AS '/yet/another/path';
Assign the name of the directory to a variable:
strDirectory_to_use := 'DIRECTORY_1';
Use the variable when opening a file:
-- References /some/path/filename.txt
aFile := UTL_FILE.FOPEN(strDirectory_to_use, 'filename.txt', 'r');
Change the variable to contain the name of a different directory object:
strDirectory_to_use := 'DIRECTORY_2';
Now when you use the variable in a call to UTL_FILE.FOPEN it will look at the directory pointed to by directory object DIRECTORY_2:
-- References /some/other/path/filename.txt
aFile := UTL_FILE.FOPEN(strDirectory_to_use, 'filename.txt', 'r');
Best of luck.
If you want to use current working directory you can create that directory dinamically. Problem is when multiple processes try to access your procedure.
If you can ensure that only one process is using procedure at same time you can do:
create or replace procedure (mypath varchar2) as
begin
execute immediate 'CREATE OR REPLACE DIRECTORY DIRECTORY_1 AS ' || mypath;
aFile := UTL_FILE.FOPEN(DIRECTORY_1, 'filename.txt', 'r');
end;
/
If you can't ensure that only one thread will call procedure at same time it gets tricky. You can try to lookup directory.
create or replace procedure (mypath varchar2) as
dirname varchar2;
begin
select DIRECTORY_NAME into dirname from dba_directories where DIRECTORY_PATH = mypath;
if (dirname is null) then
dirname := substr(replace(replace(replace(replace(dirname,'\',''),':',''),'/',''),'.',''),1,30);
execute immediate 'CREATE OR REPLACE ' || dirname || ' AS ' || mypath;
end if;
aFile := UTL_FILE.FOPEN(dirname, 'filename.txt', 'r');
end;
/
I am trying to see if this file exists. But I'm getting this error message. I have already checked the privileges I got them. But this file is on the server side so is there something I am missing
DECLARE
vInHandle utl_file.file_type;
BEGIN
vInHandle := utl_file.fopen('IMG_UTL_DIR', 'image-file.csv', 'R');
IF utl_file.is_open(vInHandle) THEN
dbms_output.put_line('The File exists');
Else
dbms_output.put_line('The File not exists');
END IF;
END fopen;
Errors:
ORA-29283: invalid file operation
ORA-06512: at "SYS.UTL_FILE", line 536
ORA-29283: invalid file operation
ORA-06512: at line 5
If the file does not exist then you will get that error. With your code, when the file exists you will get:
anonymous block completed
The File exists
But when the file does not exist you will get:
Error report -
ORA-29283: invalid file operation
ORA-06512: at "SYS.UTL_FILE", line 536
ORA-29283: invalid file operation
ORA-06512: at line 6
29283. 00000 - "invalid file operation"
*Cause: An attempt was made to read from a file or directory that does
not exist, or file or directory access was denied by the
operating system.
*Action: Verify file and directory access privileges on the file system,
and if reading, verify that the file exists.
Note the 'a file or directory that does not exist' part of the error description. You cannot test for the file's existence like this. As far as I'm aware there is no direct way to test for a file being there; you would have to attempt to open the file and catch the exception. For example:
DECLARE
vInHandle utl_file.file_type;
eNoFile exception;
PRAGMA exception_init(eNoFile, -29283);
BEGIN
BEGIN
vInHandle := utl_file.fopen('IMG_UTL_DIR', 'image-file.csv', 'R');
dbms_output.put_line('The File exists');
EXCEPTION
WHEN eNoFile THEN
dbms_output.put_line('The File not exists');
END;
END fopen;
/
anonymous block completed
The File not exists
But the ORA-29283 exception can mean other things as well, as the description says, so it doesn't necessarily mean the file is not there - it could be there but not accessible for some other (permission-related) reason. You would also be masking the location of the actual error to some extent, and if you had multiple file operations in the block then you'd either have to wrap each one in its own begin/exception/end sub-block to specify the error, or lose the actual error point.
You're probably better off just letting the exception be raised and reported naturally, rather than catching it and replacing it with a dbms_output message which might not be retrieved and displayed by the client anyway.
So I am changing the procedure of this parse_file 'clean_files_up procedure'. I have coded the changes but after testing I realized
I am actually having a hard time understanding what is going on. I have never worked with parsing a file or utl_file so I don't entirely
undrestand the concept.
So in summary, we need it to look for a file called Files20130807.xxx with the current sysdate from a directory called NEWFILE_DIRECTORY.
IF there is no file meaning that it can not find a file matching the current sysdate it needs to run the orignial file which is located
in a different directory called ORIGINALFILE_DIRECTORY and then go the the end of the procedure. If there is a file that matches the
current sysdate then it needs to continue through the procedure. When it gets to actually opening up the file it will open the file that
matches the current sysdate from NEWFILE_DIRECTORY and then will parse the file, otherwise if the current file from NEWFILE_DIRECTORY
is open then it will need to open the original file located in ORIGNIALFILE_DIRECTORY and then will parse that file instead.
PROCEDURE clean_files_up IS
v_fileName VARCHAR2(20) := Files || to_char(sysdate, 'YYYYMMDD') || '.xxx';
v_inFile utl_file.file_type;
v_outFile utl_file.file_type;
v_line VARCHAR2(2000);
v_newLine VARCHAR2(2000);
v_count NUMBER := 1;
BEGIN
--No Files found for current date
IF (substr(v_fileName, 6, 8)) <> to_char(sysdate, 'YYYYMMDD') THEN
v_inFile := utl_file.fopen('ORIGINALFILE_DIRECTORY', 'OriginalFile.xxx', 'r');
RETURN; --go to end of procedure
END IF;
v_inFile := utl_file.fopen ('NEWFILE_DIRECTORY', 'v_fileName', 'r');
IF utl_file.is_open(v_inFile) THEN
v_outFile := utl_file.fopen('ORIGINALFILE_DIRECTORY',
'OriginalFile.xxx',
'W');
LOOP
BEGIN
utl_file.get_line(v_inFile, v_line);
IF v_line IS NULL THEN
EXIT;
END IF;
IF v_count > 1 THEN
get_new_csv_line(v_line, v_newLine);
utl_file.put_line(v_outFile, v_newLine);
utl_file.fflush(v_outFile);
END IF;
v_count := v_count + 1;
EXCEPTION
WHEN no_data_found THEN
EXIT;
END;
END LOOP;
utl_file.fclose(v_outFile);
END IF;
EXCEPTION
WHEN OTHERS THEN
Condition;
END clean_files_up;
Questions:
So I need to create a new directory called NEWFILE_DIRECTORY located in some file path /xxx/xxx/xxx that has the list of files
like ; Files20130804.xxx, Files20130805.xxx, Files20130806.xxx, Files20130807 locted in it. I don't know
where inside of this procedure I would have the new directory being created or even if I can create it within the procedure
CREATE OR REPLACE DIRECTORY newfile_directory in as '/xxx/xxx/xxx'
2.. I need to read in these files to make sure that it matches the sysdate otherwise it needs to run the original file and
then go to the end of the proceudre. This part is the IF statement right after the BEGIN. I am just confussed in how it knows
to look in the NEWFILE_DIRECTORY to find the matching file name Files20130807.xxx to see if it is a match or not.
3.. This is a similiar question to #2 but how does (after the first End IF;) it know where the file path for NEWFILE_DIRECOTRY
and ORIGINALFILE_DIRECTORY is located without giving or defining a path ?
4.. Lastly when testing the code I noticed that after it reads in the v_inFile := utl_file.fopen ('NEWFILE_DIRECTORY', 'v_fileName', 'r');
(right after the first End IF;) it goes down to the exception without continuing through the if and to the loop.
I would really appreciate it someone could answer theses questions are at least help to understand what is going on. Also
if I need to clearfiy and of the questions (1-4) I can do that.
Answers on your questions:
1) Following code creates link from Oracle internally defined directory (can see them by selecting data from DBA_DIRECTORIES) to file system directory.
CREATE OR REPLACE DIRECTORY NEWFILE_DIRECTORY AS '/xxx/xxx/xxx'
If path '/xxx/xxx/xxx' already exists in file system, then this will be correct way.
2) If I understand you correctly, then you must check that in NEWFILE_DIRECTORY exists file with current date in it's name. It can be done with following function:
FUNCTION check_if_file_exists
(p_file_name IN VARCHAR2
,p_file_dir IN VARCHAR2)
RETURN BOOLEAN
IS
v_file utl_file.file_type;
BEGIN
v_file := utl_file.fopen(p_file_dir, p_file_name, 'R');
IF utl_file.is_open(v_file) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN UTL_FILE.invalid_path THEN
RETURN FALSE;
WHEN utl_file.invalid_operation THEN
RETURN FALSE;
END check_if_file_exists;
And your first if will be:
IF check_if_file_exists(v_fileName, 'NEWFILE_DIRECTORY') THEN
3) You can create DB directories (mapping for DB to find file system path) by "CREATE OR REPLACE DIRECTORY" (see #1)
4) You pass parameter as string value 'v_fileName' not variable v_fileName. Correct code would be:
v_inFile := utl_file.fopen ('NEWFILE_DIRECTORY', v_fileName, 'r');
Janis Baiza thank you for the answer it really helped me to understand what was going on.
I actually found that this will check to see if the file exists in the current directory as well and if it does then outputs that it exists and if it doesn't then out put it doesn't exist and run the original file then return to end of procedure.
utl_file.fgetattr ('NEWFILE_DIRECTORY', v_fileName, v_check_fileEX, v_fLength, v_Bsize );
IF v_check_fileEX THEN
dbms_output.put_line('file exists');
END IF;
IF NOT v_check_fileEX THEN
dbms_output.put_line('file does not exist');
v_inFile := utl_file.fopen('ORIGINALFILE_DIRECTORY', 'OriginalFile.xxx', 'r');
RETURN;
END IF;