Inserire un array in una stringa

di il
11 risposte

Inserire un array in una stringa

Salve a tutti..

Sono nuovo del forum.

Ho alcune basi (python, bash, awk, vb6, php) e sto prendendo conoscenza con delphi.

In questo momento sono alle prese nella lettura di file grafici per scoprire in quale formato è fatto.

In pratica ho fatto questo, ma non riesco ad inserire i caratteri letti in una stringa per poi poter confrontarla e vedere con quale formato è stata scritta.

Leggendo un po' qua, un po là, sono riuscito a fare questo per la lettura:

var
  myFile    : File;
  Mess, a   : string;
  oneByte   : byte;
  i, count  : Integer;
  byteArray : array[1..8] of byte;
 

  AssignFile(myFile, nomefile);
  FileMode := fmOpenRead;

  Reset(myFile, 8);

  messaggio(100, 'Lunghezza byteArray = '+inttostr(Length(byteArray)));
  // qui leggo semplicemente la lunghezza della stringa da legger (8 byte)

  BlockRead(myFile, byteArray, length(byteArray), count);
  //Leggo i dati dal file e li inserisco nell'array

  CloseFile(myFile);


  messaggio(100, 'Qui arrivo ' + string(char(byteArray[1])+char(byteArray[2])+char(byteArray[3])+char(byteArray[4])+char(byteArray[5])+char(byteArray[6])+char(byteArray[7])+char(byteArray[8])));
  // in questo converto i char dei vary byte in una stringa e mi mostra la finestra con i dati letti, e funziona bene.

 // Dopodichè ho provato ad inserire in una variabile stringa i vari vìbyte tramite ciclo for
  for i := 1 to length(byteArray) do
  begin
    Mess := Mess + str(char(byteArray[i]));
  end;

ma ogni volta che provo a scrivere sulla stringa il sistema si pianta,

Ho provato anche a leggere i dati non con byte ma impostando la lunghezza della stringa ad 8 e leggere i dati, ad inserire tutti i byte come quando mostro ('Qui arrivo')  ma niente da fare. Ho utilizzato anche la conversione SetString, ma niente, quando provo ad inserire i dati nella stringa il sistema si pianta.

Qualche aiuto?

Grazie a tutti

Sergio

11 Risposte

  • Re: Inserire un array in una stringa

    03/05/2023 - sper ha scritto:


    Ho alcune basi (python, bash, awk, vb6, php) e sto prendendo conoscenza con delphi.

    Quale versione di Delphi stai utilizzando?
    Per capire quali strumenti hai a disposizione o meno, è una informazione senz'altro utile.

    03/05/2023 - sper ha scritto:


    In pratica ho fatto questo, ma non riesco ad inserire i caratteri letti in una stringa per poi poter confrontarla e vedere con quale formato è stata scritta.

    Le funzioni che stai utilizzando sono molto vecchie, risalenti al Pascal “classico” e presenti per compatibilità all'indietro: certo, si possono comunque utilizzare, ma esistono mezzi migliori ad oggi per ottenere gli stessi risultati con codice più leggibile e maggiori funzionalità gestite in automatico.

    Ad esempio, per la lettura di file binari puoi usare la classe TFileStream: vedi la sua documentazione.

    Nel caso tu debba leggere file binari da ricondurre a testo, allora puoi combinare questa classe con TStreamReader, e anche di questa trovi la documentazione ufficiale.

    In questo thread invece, trovi un uso dello Stream per trasferire dati su una stringa (te lo cito giusto come esempio di riferimento, poi su Google ne trovi tantissimi altri).

    Se non risolvi, spiega meglio qual è l'obiettivo preciso in modo da capire come meglio implementare la soluzione più consona.

    Ciao!

  • Re: Inserire un array in una stringa

    Ciao Alka,

    grazie per la risposta.

    Ho cercto di seguire i link che mi hai mandato, ma devo ammettere che non sono riuscito a capire un gran che.

    Ho cercato di seguire gli esempi, ma purtroppo andava sempre in errore e/o non riusciva a compilare.

    In pratica dovrei "semplicemente" (nota il virgolettato) 8 byte di questi file in una stringa.

    Come dicevo ho cercato in tutti i modi (senz'altro non con quello giusto) di riempire i byte (e ci sono riuscito) e poi mettere i caratteri in una stringa; poi leggere direttamente in una stringa questi 8 byte, ma non sono proprio riuscito.

    Ora poi mi da questo errore che non so proprio come risolvere fermandosi in una riga colorandola di rosso;

    Questo ilcodice e la riga dove si ferma:

    var
       myFile    : File;
       Mess, a, Line   : string;
       oneByte   : byte;
       i, count  : Integer;
       Reader: TStreamReader;
       Buffer: TCharArray;
       ByteCount: Integer;
    
       byteArray : array[1..8] of byte;
       RTFAnsiString : AnsiString;
       Ch            : Char;
    begin
    
       Mess := '';
       Reader := TStreamReader.Create((TFileStream.Create(nomefile, fmOpenRead),TEncoding.UTF8);
    
       i := 1;
       while Reader.Peek() >= 0 do
       begin
         { Read the next character. }
        Ch := Char(Reader.Read());
         if Ch = #$0A or i <> 8 then
         begin
           Line := '';
           breack;
         end
         else
          begin
            Line := Line + Ch;
            i := i + 1;
          end;
      end;
    
    
    W1050 WideChar reduced to byte char in set expressions.  Consider using 'CharInSet' function in 'SysUtils' unit. 
  • Re: Inserire un array in una stringa

    03/05/2023 - sper ha scritto:


    Ho cercto di seguire i link che mi hai mandato, ma devo ammettere che non sono riuscito a capire un gran che.

    Approfondisci anche la documentazione. Comunque sia, senza sapere cosa non è chiaro, difficile aiutare.

    03/05/2023 - sper ha scritto:


    Ho cercato di seguire gli esempi, ma purtroppo andava sempre in errore e/o non riusciva a compilare.

    Anche qui, senza sapere quali sono gli errori a runtime o di compilazione, non è che io possa dire molto.

    03/05/2023 - sper ha scritto:


    In pratica dovrei "semplicemente" (nota il virgolettato) 8 byte di questi file in una stringa.

    Quel “virgolettato” si deve però tradurre in qualcosa di preciso e di tecnico, altrimenti non ne usciamo.

    03/05/2023 - sper ha scritto:


    Come dicevo ho cercato in tutti i modi (senz'altro non con quello giusto) di riempire i byte (e ci sono riuscito) e poi mettere i caratteri in una stringa; poi leggere direttamente in una stringa questi 8 byte, ma non sono proprio riuscito.

    I byte non sono da riempire: al massimo, li leggi dal file.

    Analogamente, non ha senso “mettere byte in una stringa”: da un lato hai dei byte, da un lato hai una stringa, quindi per passare dall'uno all'altro deve essere chiaro qual è il tipo di operazione che deve essere fatto.

    Cosa devi rappresentare? Il valore numerico del byte letto?
    Oppure il byte rappresenta un carattere espresso secondo una determinata codifica?

    La programmazione è un lavoro di precisione, quantomeno occorre comprendere cosa rappresentano quei byte e qual è il tipo di risultato che vuoi ottenere, e se l'input di byte è riconducibile all'output richiesto, altrimenti è inutile procedere con la scrittura di un programma poiché questo darà solamente errori, in esecuzione se non in fase di compilazione, poiché scrivere codice significa implementare una soluzione che lavora su dati dei quali si hanno le idee chiare di cosa rappresenta il punto di arrivo e il traguardo da raggiungere.

    Definisci i dettagli che sono dubbi e poi vediamo qual è lo strumento adatto per risolvere l'esigenza.

  • Re: Inserire un array in una stringa

    Scusami Alka, hai perfettamente ragione….

    In pratica dovrei controllare all'interno di file grafici (png, jpg, bmp,gif, tiff)  perchè ho file che devono essere caricati e non hanno l'estensione. Quella la devo mettere io.

    Detto questo ho pensato di leggere gli header dei file e vedere cosa c'è scritto in base al formato di scrittura utilizzato per l'immagine come di seguito:

    Come vedi in questo file c'è scritto GIF che è appunto la sua codifica.

    Ho pensato allora di leggere i primi 8 byte dal file dal file per poter fare il lavoro.

    Ho fatto altri lavori come questo, cioè dileggere le intestazioni per alrtri file in VB6 e python ed in entrambi (con python un po' più complesso) leggevo i byte iniziali con (vb6 molto più semplicemente, con python comunque dovevo decodificarli).

    Mi ricordo con VB che potevo dimensionare una stringa per la lettura di tot byte ed averla nella stringa per poi fare il controllo… Con mia gioia sono riuscito a leggere questi 8 byte ed a mostrarli concatenandoli in un form per la visualizzazione con string(char(byteArrai[1])+ char(bytearray[2]) ecc, ma quando lo andavo ad inserire in una stringa si interrompeva l'elaborazione ed usciva dal programma senza alcuna informazione.

    Ho provato anche le altre vie come ti dicevo, ma non ci sono riuscito.

    Il delphi che uso è embarcadero

    Grazie ancora e scusami il disturbo..

    Sergio

  • Re: Inserire un array in una stringa

    Oggi non è giorno quindi se non vaneggio più del solito.

    Dal codice iniziale due cose. Nel comando reset

    Reset(myFile, 8);

    hai scritto ,8 quindi ogni record è lungo 8 byte.

    quindi nel comando

    BlockRead(myFile, byteArray, 1, count);

    per leggere 8 byte metti 1 solo record e il numero viene ritornato in count.

  • Re: Inserire un array in una stringa

    03/05/2023 - sper ha scritto:


    Detto questo ho pensato di leggere gli header dei file e vedere cosa c'è scritto in base al formato di scrittura utilizzato per l'immagine come di seguito […]

    Ok, ora la tematica è più chiara, ma non vedo onestamente l'utilità di trasformare quei caratteri in una stringa.

    Mi spiego: anche se i primi byte corrispondono di fatto a un testo, così come si vede nella schermata, perché convertirli necessariamente in stringa? E' sufficiente controllare che i primi byte corrispondano alla sequenza attesa, ossia che abbiano i valori che ci si aspetta, per poter decretare di cosa si tratta, senza necessariamente doverli trattare come testo.

    Ti riporto qui di seguito una prova fatta al volo di una possibile implementazione che controlla i primi byte del file per accertarsi che sia una GIF:

    uses
      System.Classes, System.SysUtils;
    
    function IsImageGif(const APath: string): Boolean;
    var
      LReadBuffer: TBytes;
      LReadCount, LHeaderLength: Integer;
      LStream: TStream;
    const
      GifBytes: array[0..4] of Byte = ($47, $49, $46, $38, $39); // GIF89
    begin
      LStream := TFileStream.Create(APath, fmOpenRead);
      try
        LHeaderLength := Length(GifBytes);
    
        SetLength(LReadBuffer, LHeaderLength);
        LReadCount := LStream.Read(LReadBuffer, LHeaderLength);
    
        if LReadCount < LHeaderLength then
        begin
          Result := False;
          Exit;
        end;
    
        Result := CompareMem(LReadBuffer, @GifBytes, LHeaderLength);
      finally
        LStream.Free;
      end;
    end;

    Nell'esempio si può notare l'uso della classe TFileStream per aprire il file in lettura.

    C'è poi la dichiarazione di un array di costanti (valori di tipo byte) inizializzato con quelli che sono i byte che ci si aspetta di trovare all'inizio del file, denominato GifBytes.

    Nel codice, si dimensiona un buffer per contenere i primi 5 byte del file (l'equivalente della lunghezza dell'header da controllare) e si cerca di leggerli direttamente dal file.

    Se il numero di byte letti (LReadCount) è inferiore a quelli attesi, si restituisce un esito negativo (non è senz'altro una GIF perché il file non è lungo abbastanza nemmeno per la sua intestazione).

    Se invece si riesce a leggere il numero necessario di byte, usando CompareMem() si confrontano i due buffer, quello con l'header atteso e quello con i byte dell'header acquisito: il responso è positivo se il contenuto delle due aree di memoria coincidono.

    Usando il costrutto try…finally, si garantisce la distruzione dell'oggetto TStream e quindi la chiusura del file sottostante.

    Ovviamente, una implementazione analoga può essere riscritta e fattorizzata in chiave OOP per supportare altri formati riducendo la duplicazione del codice, ma è sufficiente a rendere l'idea.

  • Re: Inserire un array in una stringa

    Grazie alka,

    se permetti vorrei capirlo per poterlo adattare ad altri formati

    Per come hai suggerito tu ho fatto questa implementazione:

    Nella dichiarazione ho messo questo codice

    const
     GifBytes89: array[0..5] of Byte = ($47, $49, $46, $38, $39);                  // GIF89
     GifBytes87: array[0..5] of Byte = ($47, $49, $46, $38, $37);                  // GIF89
     PngBytes  : array[0..8] of Byte = ($89, $50, $4E, $47, $0F, $0A, $1A, $0a);   // PNG
     BmpBytes  : array[0..2] of Byte = ($42, $4D);                                 // BMP
     JpgBytes  : array[0..2] of Byte = ($FF, $D8);                                 // JPG
     TiffIBytes: array[0..2] of Byte = ($49, $49);                                 // TIFFI
     TiffMBytes: array[0..5] of Byte = ($4D, $4D);                                 // GIF89
    

    e nella ricerca ho trasformato così

     {
      Controllo se il file è in formato GIF89
      }
    
      LStream := TFileStream.Create(APath, fmOpenRead);
      try
        LHeaderLength := Length(GifBytes89);
    
        SetLength(LReadBuffer, LHeaderLength);
        LReadCount := LStream.Read(LReadBuffer, LHeaderLength);
    
        if LReadCount < LHeaderLength then
        begin
          Result := False;
          Exit;
        end;
    
        Result := CompareMem(LReadBuffer, @GifBytes89, LHeaderLength);
    
      finally
        LStream.Free;
      end;
      if Result := True
      begin
         Result := 'gif';
         Exit;
      end:
    
      {
      Il formato non è GIF89
      Controllo se il file è in formato GIF87
      }
    
      LStream := TFileStream.Create(APath, fmOpenRead);
      try
        LHeaderLength := Length(GifBytes87);
    
        SetLength(LReadBuffer, LHeaderLength);
        LReadCount := LStream.Read(LReadBuffer, LHeaderLength);
    
        if LReadCount < LHeaderLength then
        begin
          Result := False;
          Exit;
        end;
    
        Result := CompareMem(LReadBuffer, @GifBytes87, LHeaderLength);
    
      finally
        LStream.Free;
      end;
      if Result := True
      begin
         Result := 'gif';
         Exit;
      end:
    

    In pratica ho moltiplicato la tua elaborazione per tutti i formati che vorrei trovare.

    Però ho un dubbio.

    All'inizio apri il file con 

    LStream := TFileStream.Create(APath, fmOpenRead);

    ma non trovo (o non l'ho trovata) alcuna istruzione per chiudere il file

    Basta mettere 

    LStream.close()

    Grazie :)

  • Re: Inserire un array in una stringa

    Ho provato a farlo girare e mi dava errore nella dichiarazione dei byte. 

     GifBytes89 : array[0..4] of Byte = ($47, $49, $46, $38, $39);                  // GIF89
     GifBytes87 : array[0..4] of Byte = ($47, $49, $46, $38, $37);                  // GIF89
     PngBytes   : array[0..7] of Byte = ($89, $50, $4E, $47, $0F, $0A, $1A, $0a);   // PNG
     BmpBytes   : array[0..1] of Byte = ($42, $4D);                                 // BMP
     JpgBytes   : array[0..1] of Byte = ($FF, $D8);                                 // JPG
     TiffIBytes : array[0..1] of Byte = ($49, $49);                                 // TIFF-I
     TiffMBytes : array[0..1] of Byte = ($4D, $4D);                                 // TIFF-M
    

    Corretto.

    Oltre a questo ho anche modificato la definizione della funzione dove deve ritornare o false/nil o l'estensione da inserire.

    function leggitipoimmagine(nomefile : string): string;

    Non ho ben capito se il ritorno deve essere messo in Result o quant'altro come, per esempio comparare la memoria e se uguale ritornare l'estenzione

        Result := CompareMem(LReadBuffer, @GifBytes89, LHeaderLength);
    
      finally
        LStream.Free;
      end;
      if Result := True
      begin
         Result := 'gif';
         Exit;
      end:
  • Re: Inserire un array in una stringa

    04/05/2023 - sper ha scritto:


    All'inizio apri il file con 

    LStream := TFileStream.Create(APath, fmOpenRead);

    ma non trovo (o non l'ho trovata) alcuna istruzione per chiudere il file

    La chiusura del file avviene contestualmente alla distruzione dell'oggetto, fatta con LStream.Free().

    04/05/2023 - sper ha scritto:


    Oltre a questo ho anche modificato la definizione della funzione dove deve ritornare o false/nil o l'estensione da inserire.

    Questa strada è assolutamente da evitare.

    Pur essendo possibile, Delphi è un linguaggio tipizzato: il valore di ritorno deve appartenere a un tipo dichiarato, e se si tratta di una stringa non può essere un booleano, o viceversa.

    Tutt'al più, puoi decidere di restituire una stringa che sia vuota in caso non sia possibile riconoscere il formato, o l'estensione da attribuire al file.

    04/05/2023 - sper ha scritto:


    Non ho ben capito se il ritorno deve essere messo in Result o quant'altro come, per esempio comparare la memoria e se uguale ritornare l'estenzione […]

    Il pezzo di codice che segue non è assolutamente corretto:

    if Result := True
      begin
         Result := 'gif';
         Exit;
      end:

    E' sbagliato l'uso dell'operatore di assegnazione, è sbagliato l'uso di valori appartenenti a tipi diversi (vedi discorso precedente), è sbagliato il “:” che segue l'ultimo end.

    Questo mi permette di fare un inciso che sembrerebbe scontato ma che non lo è affatto: prima di scrivere codice con un linguaggio, bisogna conoscere il linguaggio. Se non conosci la sintassi del linguaggio Delphi, prima devi approfondire quella, poi hai la facoltà di passare a qualcosa di più complesso e articolato.

    Per dirne una, il codice che hai scritto potrebbe essere fortemente rifattorizzato, usando la OOP o con altre architetture, dato che fondamentalmente per ogni formato stai duplicando la stessa procedura, cambiando solo un paio di parametri: i byte attesi a inizio file e il formato corrispondente.

  • Re: Inserire un array in una stringa

    Bene alka,

    sono riuscito nel mio intento..

    Grazie al tuo codice sono riuscito a vedere tutti i tipi di immagini che mi interessavano ed a mettere l'estensione giusta per il caricamento dell'immagine (per poi ripristinare come prima).

    Sei veramente forte!!!

    Grazie ancora dei consigli

  • Re: Inserire un array in una stringa

    04/05/2023 - sper ha scritto:


    sono riuscito nel mio intento..

    Ottimo! Tutto è bene quel che finisce…. e basta. :D

Devi accedere o registrarti per scrivere nel forum
11 risposte