Voraussetzungen

Um auf Dateien zugreifen zu können müssen bestimmte Voraussetzungen gegeben sein:

  1. Die Dateien müssen in einem Ordner liegen, der vom Datenbankserver aus zugänglich ist
  2. Der User unter dem der Oracle Dienst läuft muss Lese-/Schreibberechtigung auf die Dateien haben
  3. Es existiert ein Oracle Directory Objekt, das auf das Verzeichnis verweist
  4. Dem Datenbankuser wurde Lese-/Schreibberechtigung auf das Directory Objekt erteilt

Angenommen

  • die Datenbank läuft unter Windows auf einem PC,
  • die Dateien liegen auf einer Partition D:
  • im Verzeichnis D:\marcus\ora\doc

Bedingung 1 und 2 sind in der Regel bereits erfüllt, wenn nicht explizit Zugangsbeschränkungen erteilt wurden.

Das Directory muss von einem DBA erstellt werden, oder einem User, der die entsprechende Berechtigung hat

CREATE OR REPLACE DIRECTORY doc
    AS 'D:\marcus\ora\doc';
GRANT READ, WRITE ON DIRECTORY doc TO hr;

Wichtig: beim Erstellen wurde hier zwar der Directoryname klein geschrieben, wird von Oracle aber immer in Großbuchstaben angelegt und muss deshalb mit 'DOC' referenziert werden.

Die vorhandenen Directories und die zugewiesenen Berechtigungen können über all_directories geprüft werden. Die Bedeutung der Java Privilegien wird weiter unten erläutert.

SELECT  ad.directory_name "Directory Name"
       ,ad.directory_path "Path"
       ,atp.grantee "Grantee"
       ,atp.privilege "Privilege"
       ,ujp.type_name "Java Priv. Typ"
       ,ujp.action "Java Priv."
FROM    all_directories ad
        JOIN all_tab_privs atp
          ON (ad.directory_name = atp.table_name)
        LEFT JOIN user_java_policy  ujp
          ON (ujp.name = ad.directory_path)
ORDER BY ad.directory_name;

Dateien lesen

Beim Öffnen einer Datei wird ein Handler erzeugt, mit dem man später auf die Datei zugreifen kann

utl_file.FILE_TYPE

Um eine Datei lesen zu können muss man ihren Namen kennen; eine Möglichkeit dies zu umgehen beschreibe ich später.

Datei öffnen

DECLARE
  v_fileHandle            utl_file.FILE_TYPE;
  v_line                  VARCHAR2(32767);
BEGIN
  v_fileHandle   := utl_file.fopen('DOC','testfile.txt','R',32767);

In diesem Beispiel wird im Directory DOC eine Datei namens testfile.txt für lesenden Zugriff geöffnet.

Inhalt zeilenweise lesen

  utl_file.get_line (
         v_fileHandle
        ,v_line
        ,32767
        );

Dies liest eine Zeile mit der maximal möglichen Länge. Wird eine kleinere Zahl angegeben, dann wird möglicherweise nur ein Teil der Zeile gelesen, der nächste Lesevorgang beginnt dann nicht in der nächsten Zeile, sondern setzt am vorherigen an.

Datei schließen

  utl_file.fclose(v_fileHandle);
END;
/

Datei direkt in ein CLOB laden

Eine Datei kann auch direkt in ein CLOB geladen werden, ohne sie Zeile für Zeile zu lesen. Hierzu gibt es dbms_lob.loadClobFromfile.

Eine mögliche Implementierung ist die Prozedur getClobFromFile in dem unten zum Herunterladen angebotenen Package mam_file.

Dateien schreiben

Datei öffnen

DECLARE
  v_fileHandle            utl_file.FILE_TYPE;
BEGIN
  v_fileHandle   := utl_file.fopen('DOC','testfile.txt','W',32767);

Wird die Datei zum Schreiben geöffnet, wird eine leere Datei erzeugt. Besteht die Datei bereits wird sie ohne Fehlermeldung überschrieben. Um dies zu vermeiden kann mit utl_file.fgetattr die Existenz geprüft werden

Um Text an eine bestehende Datei anzuhängen kann die Option 'A' (append) beim Öffnen gewählt werden.

Text schreiben

  utl_file.put_line (
         v_fileHandle
        ,'Lorem ipsum'
        );

utl_file.put_line schreibt den übergebenen Text und hängt anschließend einen Zeilenumbruch an. Soll in der gleichen Zeile weiterer Text angefügt werden, dann erfolgt das Schreiben mit utl_file.put

CLOB schreiben

Um ein CLOB in eine Datei zu schreiben kann man das zeilenweise über utl_file machen, oder man verwendet

  dbms_xslprocessor.clob2file (
         v_clob
        ,'DOC'
        ,'<filename>'
        ,
        );

Für eine Diskussion was es mit verschiedenen Zeichensätzen auf sich hat siehe auch

Verzeichnisinhalte lesen

Wie oben beschrieben bietet Oracle von sich aus keine Möglichkeit den Inhalt eines Verzeichnisses zu lesen.

Abgesehen von der XE Version steht in der Datenbank eine JVM zur Verfügung, die es erlaubt mit Java Mitteln die gewünschten Informationen auszulesen.

Zunächst muss dem User vom DBA der Zugriff über Java erlaubt werden

BEGIN
    dbms_java.grant_permission (
         'HR'--User
        ,'SYS:java.io.FilePermission'--Dateizugriff
        ,'D:\marcus\ora\doc'--Pfad! nicht Directory Name
        ,'read'--Berechtigung
        );
END;
/

Anschließend wird der Code zum Zugriff eingespielt. Eine Implementierung kann zusammen mit weiteren Dateifunktionen heruntergeladen werden.

Ein Zugriff auf ein Verzeichnis mit diesem Package kann so aussehen:

DECLARE
   v_directory           all_directories.directory_name%TYPE := 'DOC';
   tab_filelist          mam_file.t_filelist;
BEGIN
   --Lies alle Dateien mit der Endung .xml
   tab_filelist  := mam_file.getFilelist(v_directory,'.xml');
   IF tab_filelist.COUNT > 0 THEN
      <<loop_alleDateien>>
      FOR i IN tab_filelist.FIRST .. tab_filelist.LAST LOOP
         -- Tu irgendwas mit den Dateien
      END LOOP loop_alleDateien;
   END IF;
END;
/

Alternative

Eine simple Alternative, wenn du nur ein Verzeichnis auslesen willst: mam_file_java_util

Es genügt ein Select um Dateiattribute wie Name, Änderungsdatum und Größe auszulesen.

SELECT  *
FROM    TABLE(mam_file_java_util.ls('MY_DIRECTORY'))
WHERE   name LIKE 'T%'
AND     modified >= SYSDATE - 3
AND     file_size > 10;

Zusätzlich können Dateien verschoben oder gelöscht werden. Warum, wenn man es auch mit utl_file kann?

Beim Kopieren binärer Dateien kann es zu Problemen kommen, da ist Java überlegen.
Das Löschen habe ich implementiert, weil auf einen Windows CIFS-Share, der auf den Linux-DB-Server gemountet war, das Problem auftauchte, dass Dateien mit utl_file scheinbar gelöscht wurden, in Wirklichkeit aber nur das hidden-Flag gesetzt wurde. Bis heute konnte ich nicht ergründen woran das lag. Mit Java funktioniert es reibungslos

Herunterladen

Das verlinkte Package enthält Hilfsfunktionen für Dateizugriffe.
Hinweis: In dem Package wird bei Dateizugriffen immer geprüft, ob die notwendigen Berechtigungen vorliegen. Bei häufigem Öffnen/Schließen ist das nicht notwendig. Es kann vor dem ersten Zugriff direkt geprüft werden, die weiteren Zugriffe erfolgen dann direkt mit utl_file.

Zur Verwendung mit der XE11-Edition müssen in mam_file die Zugriffe auf die Funktionen zum Auflisten der Ordnerinhalte gelöscht werden, da diese Version kein Java enthält!

oracle@matzberger.de Für Kontakte aller Art, auch Fehlermeldungen zum Programm Impressum