[NEWSboard IBMi Forum]
Seite 1 von 4 1 2 ... Letzte
  1. #1
    Registriert seit
    Jan 2012
    Beiträge
    1.102

    Unicode / UTF-8 Streamfile lesen

    Hallo,
    ich habe mir einige Serviceprogramme geschrieben, mit denen ich Streamfiles bequem lesen kann. Ich nutze dazu die UNIX Type APIs. Z.B. "read".

    Code:
    D AnzBytes        S             10U 0
    D AnzGelesen      S             10P 0
    D buffer          S          64000A
    AnzGelesen = read(handle:%addr(buffer):AnzBytes)
    Das ganze funktioniert allerdings nur, wenn in der Streamfile ein Single Byte Character Set drinsteht. Wenn ich eine Streamfile erzeuge, die UTF-8 oder Unicode beinhaltet, stürzt das Programm ab.

    In der Doku zu "read" steht auch, dass damit nur eine genaue Anzahl von Bytes gelesen wird. Ich will aber eigentlich keine Bytes lesen, sondern Zeichen.

    Hat jemand dieses Problem bereits gelöst? Gibt es eine empfehlenswerte API-Funktion, mit der man Zeichen (auch Unicode oder UTF-8) lesen kann?

    Vielleicht fällt ja jemandem etwas über die Feiertage ein! Im Voraus vielen Dank!

    Frohe Ostern.

    Dieter

  2. #2
    Registriert seit
    Feb 2001
    Beiträge
    20.207
    Vergiss die alten C-API's und nimm einfach SQL.
    http://newsolutions.de/forum-systemi...435#post106435
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  3. #3
    Registriert seit
    Jan 2012
    Beiträge
    1.102
    Vielen Dank für deine Antwort.

    Grundsätzlich ginge das mit SQL. Was mich stört, ist allerdings, dass ich dann die ganze Datei immer "am Stück" handeln muss. Mit den reads und seeks könnte ich mich auch in sehr großen Dateien bewegen und die interessanten Stellen lesen.

    Wenn ich keine besseren APIs finde, werde ich es aber wohl erstmal mit SQL umsetzen. Wenn ich den ganzen SQL-Code in einem Serviceprogramm kapseln möchte, dem ich einen Pfad und Dateinamen mitgebe und das mir dann den Dateiinhalt komplett als String zurückgibt, müsste ich im Serviceprogramm ja schon ziemlich große Datenstrukturen für SQLTYPE deklarieren. Da könnte schnell die 16 MB Speichergrenze erreicht werden. Gerade bei Unicode.

  4. #4
    Registriert seit
    Aug 2001
    Beiträge
    2.869
    Du kannst auch mit SQL gezielt auf Daten zugreifen und dir nur das rausholen, was Du brauchst.
    File-Referenz-Variablen kannst Du mit SQL-Funktionen genau wie alphanumerische Felder behandeln, d.h. mit POSSTR oder LOCATE kannst Du positionieren und suchen, mit SUBSTR kannst Du Daten gezielt herauslesen und dann in eine (kürzere) Host-Variable ausgeben.
    ... und Du bist auch nicht auf 16MB beschränkt, sondern kannst die ganzen (möglichen) 2GB verarbeiten. (Die Daten werden überigens nicht kopiert)

    Beispiel:
    Code:
     DCL-S MyClobFile  SQLTYPE(CLOBFILE) CCSID(1208);
    ...
     MyCLOBFile_Name = %Trim(ParIFSFile);                               
     MyCLOBFile_NL   = %Len(%Trim(MyCLOBFile_Name));                    
     MyCLOBFile_FO   = SQFRD;                            //Read Only    
                                                                        
     For Index =  1 to 15;                                              
         Start = (Index-1) * RowLen + 1;                                
         Exec SQL Set :MyText = Substr(:MyCLOBFile, :Start, :RowLen);   
         Dsply MyText;                                                  
         If    SQLCODE = 100 or SQLCODE < *Zeros                        
            or %Len(%Trim(MyText)) = *Zeros;                            
            Leave;                                                      
         EndIf;                                                         
     EndFor;
    Birgitta
    Birgitta Hauser

    Anwendungsmodernisierung, Beratung, Schulungen, Programmierung im Bereich RPG, SQL und Datenbank
    IBM Champion seit 2020 - 4. Jahr in Folge
    Birgitta Hauser - Modernization - Education - Consulting on IBM i

  5. #5
    Registriert seit
    Feb 2001
    Beiträge
    20.207
    Siehst du, geht doch alles.
    Und wieso 16MB-Grenze?
    Wenn du auf *TERASPACE gehst, in der gesamten Prozesskette, kannst du Speicher bis 2Tera ansprechen. Da platzt dir wahrscheinlich eher die Platte.
    Im Service erbst du das Speichermodell und der Rufer gibt sein Speichermodell vor. Alles sehr flexibel.
    Je ACTGRP kann ein anderes Speichermodell gewählt werden.

    Vorteil von SQL:
    Alle möglichen String-Funktionen können verwendet werden.
    Alle CCSID's können verwendet werden.
    Automatische CCSID-Wandlung inclusive.

    Wenn du mein Beispiel siehst, nehme ich als Ziel DBCLOB, das ist UCS2-Code. Im Singlestorage max. 8 MB. Aber so große Dateien habe ich im Schnittstellenbereich nicht gehabt, und dann gibts ja noch Birgittas Hinweise.

    Ich nehme af diesem Weg z.B. EDI-Dateien auseinander. Für EDI-XML's definiere ich passende Strukturen und verwende dann den XML-INTO.
    Übrigens generell in UCS2/UTF16, da schon mal gerne der Job auf 65535 belassen wird.

    Nachtrag:
    Da ein Service ja von verschiedenen Programmteilen aufgerufen werden kann, muss man sich natürlich Zerstückelungslogiken sehr genau überlegen. Nicht dass während der Verarbeitung einer dazwischen grätscht.
    Interessant sind Ansätze wie CALLBACK-Verarbeitung (Procedurpointer). In diesem Fall ist ein Service auch Rekursiv benutzbar.
    Oder man generiert sich einen "FileControlBlock" (kennt man irgendwoher), der relevante Stati festhält. Da könnte man auch Repositionierungen durchführen und viele Dateien gleichzeitig bearbeiten. SQL hält die Datei nämlich nicht geöffnet.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  6. #6
    Registriert seit
    Aug 2014
    Beiträge
    179
    Du kannst auch mit SQL gezielt auf Daten zugreifen und dir nur das rausholen, was Du brauchst.
    File-Referenz-Variablen kannst Du mit SQL-Funktionen genau wie alphanumerische Felder behandeln, d.h. mit POSSTR oder LOCATE kannst Du positionieren und suchen, mit SUBSTR kannst Du Daten gezielt herauslesen und dann in eine (kürzere) Host-Variable ausgeben.
    ... und Du bist auch nicht auf 16MB beschränkt, sondern kannst die ganzen (möglichen) 2GB verarbeiten. (Die Daten werden überigens nicht kopiert)
    Welcome back Birgitta,

    ich hoffe, Du bereicherst weiterhin dieses Forum und lässt Dich nicht wieder vertreiben

    Herzliche Grüße
    Rainer Ross

  7. #7
    Registriert seit
    Aug 2001
    Beiträge
    2.869
    Zitat Zitat von Fuerchau Beitrag anzeigen
    Siehst du, geht doch alles.
    Und wieso 16MB-Grenze?
    Wenn du auf *TERASPACE gehst, in der gesamten Prozesskette, kannst du Speicher bis 2Tera ansprechen. Da platzt dir wahrscheinlich eher die Platte.
    Im Service erbst du das Speichermodell und der Rufer gibt sein Speichermodell vor. Alles sehr flexibel.
    Je ACTGRP kann ein anderes Speichermodell gewählt werden.
    Dann versuch doch mal eine Variable oder Datenstruktur > 16MB zu definieren oder mit SQL einen Pointer zu verarbeiten.

    Birgitta
    Birgitta Hauser

    Anwendungsmodernisierung, Beratung, Schulungen, Programmierung im Bereich RPG, SQL und Datenbank
    IBM Champion seit 2020 - 4. Jahr in Folge
    Birgitta Hauser - Modernization - Education - Consulting on IBM i

  8. #8
    Registriert seit
    Jan 2012
    Beiträge
    1.102
    Zitat Zitat von Fuerchau Beitrag anzeigen
    Siehst du, geht doch alles.
    Und wieso 16MB-Grenze?
    Wenn du auf *TERASPACE gehst, in der gesamten Prozesskette, kannst du Speicher bis 2Tera ansprechen.
    Ich meine, *TERASPACE bringt nur etwas bei eigener Speicherallozierung mit %alloc.

    Die Speichernutzung für "normale" RPG-Variablen ist meiner Meinung nach auf 16MB begrenzt. Wobei ich mir im Moment nicht sicher bin, ob die 16 MB pro Job, pro Call-Ebene oder pro ACTGRP gelten.

  9. #9
    Registriert seit
    Jan 2012
    Beiträge
    1.102
    Vielen Dank für die beiden Antworten. Ich werde eurem Rat folgen und das ganze mit SQL machen!

    Viele Grüße,
    Dieter

  10. #10
    Registriert seit
    Feb 2001
    Beiträge
    20.207
    Was die Pointer angeht, so muss ich sogar via SQLDA Pointer angeben (nebst SQLType und Attributen).
    Somit kann ich auch schön per %ALLOC Speicher zur Verfügung stellen.
    SQLDA's werden dann per "using" bei den entsprechenden SQL-Befehlen angegeben.
    Dann kann ich eben auch innherhalb von RPGLE wiederum mit Pointern umgehen.

    Zu beachten ist noch folgendes:
    In meinem Beispiel habe ich 8MB Unicode (CCSID 1200) verwendet. Sollte die Datei tatsächlich mal größer sein, sollte man hier dann mit LOB-Locator umgehen: GET_[DB/C]LOB_FROM_FILE.
    Der Vorteil des Locator's besteht halt darin, dass das Lesen der Datei und die Codewandlung in den Speicher nur 1x passiert.
    Anschließend kann man sich per SQL-Stringfunktionen dann die Teile herausholen.
    Dies dürfte wohl performanter sein, als sich die Daten scheibchenweise aus der Datei zu holen, zumal bei UTF-8 eine Zeichenposition direkt ja nicht errechenbar ist (UTF-8 => 1-4Byte je Zeichen).
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  11. #11
    Registriert seit
    Jan 2012
    Beiträge
    1.102
    Irgendwie klappt das bei mir noch nicht:
    Code:
    dcl-s clobFile sqltype(CLOB_FILE) CCSID(1200);
    dcl-s text varucs2(300000);
    
    
    clobFile_Name = %trim(file);
    clobFile_NL   = %len(%trim(clobFile_Name));
    clobFile_FO   = SQFRD;  //Read Only
    
    
    exec sql set :text = :clobFile;
    
    
    return text;
    Beim Kompilieren bekomme ich immer:

    "Variable TEXT nicht definiert oder nicht verwendbar. Reason: No declaration for the variable exists, the declaration is not within the current scope, or the variable does not have an equivalent SQL data type."

    Hat jemand eine Idee?

  12. #12
    Registriert seit
    Jan 2012
    Beiträge
    1.102
    Das Problem hat sich erledigt. Habe einen Doppelpunkt vor der Variable "TEXT". Der darf da nicht hin.

Similar Threads

  1. http_url_get mit unicode
    By dschroeder in forum NEWSboard Programmierung
    Antworten: 5
    Letzter Beitrag: 29-03-19, 14:56
  2. Zeichenumsetzung AS/400 nach Streamfile
    By Theo in forum IBM i Hauptforum
    Antworten: 3
    Letzter Beitrag: 02-03-18, 13:46
  3. Ausländische Zeichen in Streamfile schreiben
    By dschroeder in forum NEWSboard Programmierung
    Antworten: 7
    Letzter Beitrag: 12-12-17, 14:32
  4. Konvertieren in Unicode
    By Rainer Ross in forum NEWSboard Programmierung
    Antworten: 5
    Letzter Beitrag: 28-10-16, 17:16
  5. IFS-Streamfile in RPG bearbeiten
    By Bleil in forum IBM i Hauptforum
    Antworten: 2
    Letzter Beitrag: 13-10-01, 21:15

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • You may not post attachments
  • You may not edit your posts
  •