Autore Topic: [Risolto] Aprire, modificare e salvare files, il metodo più efficiente?  (Letto 985 volte)

Offline El Berto

  • Grande Gambero
  • ***
  • Post: 150
    • Mostra profilo
Avrei bisogno di aprire dei files, leggere dei byte a determinate posizioni, modificarli e salvare nuovamente il file.
Quale potrebbe essere il metodo più efficiente (tenendo conto che il file potrebbe avere dimensione di 100-200 MB)?
A naso mi verrebbe da fare con File.load e File.save, ma suppongo che ci siano soluzioni più "raffinate", o sbaglio?
Grazie.
« Ultima modifica: 23 Novembre 2013, 18:12:31 da El Berto »

Aldo

  • Visitatore
Re: Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #1 il: 22 Novembre 2013, 19:51:36 »
Come potrebbe essere organizzato il file da leggere?
E' qualcosa di standardizzabile o è un insieme di caratteri mischiati a "random"? :coder:

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.269
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #2 il: 22 Novembre 2013, 20:02:04 »
...suppongo che ci siano soluzioni più "raffinate", o sbaglio?
A mio modestissimo parere, nel momento in cui usi specifiche funzioni all'uopo preposte, adotti già una metodologia "raffinata". Dunque fra due previste e legittime soluzioni, si pone una duplice questione:

* che tipo di dati ti servono da manipolare successivamente ? Tipo Byte ? Tipo Stringa ?
* è necessaria la velocità nell'apertura del file ?


Avrei bisogno di aprire dei files,
Tenuto conto che devi aprire dei pesantissimi file, la risposta alla seconda domanda mi pare sia positiva. Ebbene da quel che ho potuto sempre notare, l'apertura di un file con il metodo .Load della Classe File, è molto veloce, e ben più veloce della modalità di assunzione dei dati mediante un ciclo dopo aver aperto il file con l'istruzione Open.... For Read.

Ti riporto un test di velocità che ho fatto (i valori temporali sono condizionati dalla capacità del mio PC, ma chiaramente ciò che importa è il confronto fra i tre test) mediante un file di 40 megabyte:

* modalità Open.... For Read + ciclo While...Wend (raccolta dati di tipo Byte):
Codice: gambas [Seleziona]

Public Sub Form_Open()

 Dim fl As File
 Dim b As Byte

  fl = Open "/percorso/del/file" For Read

  While Not Eof(fl)
    Read #fl, b
  Wend

  fl.Close

End


ha impiegato 7602 millisecondi;


* modalità File.Load() (raccolta dati tipo Stringa):
Codice: gambas [Seleziona]

Public Sub Form_Open()

  Dim s As String

   s = File.Load("/percorso/del/file")
 
End


ha impiegato 451 millisecondi;


* modalità Open.... For Read + sola istruzione Read a lunghezza fissa (raccolta dati tipo Stringa):
Codice: gambas [Seleziona]

Public Sub Form_Open()

  Dim fl As File
  Dim s As String

   fl = Open "/percorso/del/file"

' Lettura a lunghezza "fissa":
   Read #fl, s, Stat("/percorso/del/file").Size

  fl.Close

End


ha impiegato 31 millisecondi.


Ad ogni modo, puoi agevolmente ottenere valori di tipo Byte da valori a rappresentazione Stringa utilizzando il metodo .FromString() della Classe Byte[]:
Codice: gambas [Seleziona]

Public Sub Form_Open()

  Dim fl As File
  Dim s As String
  Dim bb As Byte[]

   fl = Open "/percorso/del/file"

   Read #fl, s, Stat("/percorso/del/file").Size

   bb = Byte[].FromString(s)

  fl.Close

End




Avrei bisogno di ... leggere dei byte a determinate posizioni, modificarli
Se utilizzi l'apertura del file con l'istruzione "Open..." puoi spostarti all'interno del flusso dei dati mediante la funzione Seek #variabile_file, indice_dei_dati  .
Esempio:
Codice: gambas [Seleziona]

Public Sub Main()

  Dim b As Byte
  Dim fl As File

  fl = Open "/percorso/del/file" For Read

' Spostiamo il puntatore del flusso al byte num. 9 (ossia il 10°):
  Seek #fl, 9
 
' Leggiamo il 10° byte :
  Read #fl, b

  fl.Close

  Print b

End
« Ultima modifica: 17 Aprile 2023, 15:57:58 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline El Berto

  • Grande Gambero
  • ***
  • Post: 150
    • Mostra profilo
Re: Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #3 il: 23 Novembre 2013, 16:26:27 »
Allora, il file è un file binario, quindi lo devo leggere e mettere i dati in un array tipo Byte[], ma mi andrebbe più comodo una cosa del tipo Short[] visto che vado a leggere una word.

Poi devo andare a suddividere i dati in blocchi da 4096 bytes, leggere la prima word (se lavoro in Short[]) o i primi 2 byte (se lavoro con Byte[]), modificarla e riscriverla; questo per tutta la lunghezza del file.

Poi dovrei anche tenere conto di come gestire il fatto che il file potrebbe essere modificato da un'altra applicazione mentre lo sto "elaborando", ma questa è una cosa che vedrò dopo....


Ho trovato in rete diversi esempi di lettura di un array da file, ma nessuno ha funzionato, provo un po' con i tuoi.
Grazie.

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.269
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #4 il: 23 Novembre 2013, 17:26:43 »
Ho trovato in rete diversi esempi di lettura di un array da file, ma nessuno ha funzionato, provo un po' con i tuoi.


Potresti anche utilizzare il metodo ''.Read()'' dei tipi vettoriali (Byte[], Short[], etc...).


Esempio: lettura di dati di tipo Byte da un file di testo e loro inserimento in un vettore di tipo Byte[ ]:
Codice: gambas [Seleziona]

Public Sub Main()

 Dim a As Byte[]
 Dim fl As File
 Dim b As Byte


   fl = Open "/percorso/del/file" For Read
  
' Impostiamo il numero di elementi dei quali il vettore sarà costituito:
   a = New Byte[Stat("/percorso/del/file").Size]
  
     a.Read(fl)

   fl.Close

' Andiamo a verificare in console:
   For Each b In a
     Print Chr(b);
   Next

End
« Ultima modifica: 24 Novembre 2013, 01:18:11 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline El Berto

  • Grande Gambero
  • ***
  • Post: 150
    • Mostra profilo
Re: Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #5 il: 23 Novembre 2013, 18:11:55 »
Ah, ecco dov'era l'inghippo!!!
In rete avevo trovato soluzioni analoghe, ma non veniva detto che dovevo inizializzare l'array con la dimensione specifica....

Comunque ho provato così e sembra funzionare:


Codice: [Seleziona]
Dim myFile As File
Dim aMyArray As Short[]
Dim Dimensione As Long



     
      ' apertura file
      myFile = Open "/home/michele/earthworm/friuli/data/bud/NI/5373/copy.bin" For Read 
      Dimensione = Stat("/home/michele/earthworm/friuli/data/bud/NI/5373/copy.bin").Size
      aMyArray = New Byte[Dimensione / 2] 
      aMyArray.Read(myFile) 
      Close myFile
     
      ' modifica valore
      aMyArray[0] = &h7927

      ' apertura file destinazione
      myFile = Open "/home/michele/earthworm/friuli/data/bud/NI/5373/copy3.bin" For Create
      aMyArray.Write(myFile)
      Close myFile

      aMyArray.Clear
      aMyArray = New Byte[Dimensione / 2]
      ' verifica scrittura
      myFile = Open "/home/michele/earthworm/friuli/data/bud/NI/5373/copy3.bin" For Read 
      aMyArray.Read(myFile)
      Close myFile


Grazie per l'aiuto!

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.269
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: [Risolto] Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #6 il: 23 Novembre 2013, 18:18:38 »
La definizione a priori del numero degli elementi del vettore non è obbligatoria. Tale numero può essere definito implicitamente e successivamente attraverso il suo progressivo incremento mediante il metodo .Add():
Codice: gambas [Seleziona]

Public Sub Button1_Click()

 Dim bb As New Byte[]
 Dim b As Byte = 99

' Verifica di quanti elementi è attualmente costituito il vettore:
   bb.Count

' Aggiungiamo un elemento (sempre avente valore 99) al vettore:
      bb.Add(b)

' Verifica di quanti elementi è ora costituito il vettore:
   bb.Count

End
« Ultima modifica: 23 Novembre 2013, 20:59:52 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline El Berto

  • Grande Gambero
  • ***
  • Post: 150
    • Mostra profilo
Re: [Risolto] Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #7 il: 24 Novembre 2013, 10:01:53 »
Mah, non so dove sbagliavo, che quando cercavo di fare .Add mi metteva errore....

L'unico problema che ho riscontrato alla fine è che quando apro lo stream non riesco a impostare BigEndian o LittleEndian (leggendo un Short[], sia con uno che con l'altro l'ordine dei byte non cambia).

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.269
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: [Risolto] Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #8 il: 24 Novembre 2013, 17:02:56 »
Mah, non so dove sbagliavo, che quando cercavo di fare .Add mi metteva errore....


Per usare il metodo .Add(), non si deve dimenticare la parola New:
Codice: gambas [Seleziona]

 Dim bb As New Byte[]

   bb.Add(99)

« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.269
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: [Risolto] Aprire, modificare e salvare files, il metodo più efficiente?
« Risposta #9 il: 25 Novembre 2013, 02:00:31 »
L'unico problema che ho riscontrato alla fine è che quando apro lo stream non riesco a impostare BigEndian o LittleEndian (leggendo un Short[], sia con uno che con l'altro l'ordine dei byte non cambia).

Ho posto nella M.L. ufficiale una domanda di carattere generico su questa proprietà .ByteOrder, ed ho ricevuto le seguenti due risposte:


" The stream ByteOrder property defines the byte order (little endian or
big endian) used by the READ and WRITE instructions when using that
stream. By default, the ByteOrder is the CPU's one.

What is not clear exactly in the previous definitions?

--
Benoît Minisini
"


" Well, I won't give you a complete project because I also have work to do but
here you have an idea: try to parse a .bmp file with Gambas. Its format is
reasonably simple (at least I can't think of a simpler "real" file format
out of the blue) and can be looked up at Wikipedia. The BMP format uses
little endian. So you explicitly have to set Stream.ByteOrder to little
endian to get the same result on all machines.

Regards,
Tobi
"
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »