C# Scrivere una struttura su un file ascii

venerdì 03 aprile 2009 - 16.35

ciuky Profilo | Newbie

ciatutti...

sto facendo degli esperimenti ed ho bisogno dei chiarimenti causa mio PERSEVERANTE niubbismo...

Ho una struttura di questo tipo:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Struttura
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string nome;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string cognome;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string indirizzo;
}

Utilizzando lo streamwriter vorrei scrivere il contenuto della struttura, correttamente valorizzata, su un file ascii sequenziale.

ho provato con
writer = new System.IO.StreamWriter("c:\\testo.txt");
writer.writeline(stuttura);
ma è probabilmente la strada sbagliata....

forse debbo utilizzare i puntatori alla struttura, ma ho veramente le idee confuse.

qualcuno è così gentile da catechizzarmi sull'argomento indicandomi qualche link o esempio?


grazie

red

aiedail92 Profilo | Expert

Ciao

Puoi renderti la vita molto semplice sfruttando la serializzazione:

Aggiungi un attributo Serializable alla tua struttura, quindi sfrutta le classi XmlSerializer o BinaryFormatter per effettuare la serializzazione e la deserializzazione (cioè salvataggio e caricamento), ad esempio in questo modo:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [Serializable()] public struct Struttura { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] public string nome; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] public string cognome; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] public string indirizzo; } void Esempio() { Struttura struttura = new Struttura(); struttura.nome = "MioNome"; struttura.cognome = "MioCognome"; struttura.indirizzo = "MioIndirizzo"; //Salva i dati XmlSerializer xmlS = new XmlSerializer(typeof(Struttura)); using (FileStream stream = new FileStream(@"C:\file.xml", FileMode.Create)) { xmlS.Serialize(stream, struttura); } //Oppure BinaryFormatter binF = new BinaryFormatter(); using (FileStream stream = new FileStream(@"C:\file.dat", FileMode.Create)) { binF.Serialize(stream, struttura); } //Carica i dati using (FileStream stream = new FileStream(@"C:\file.xml", FileMode.Open)) { struttura = (Struttura)xmlS.Deserialize(stream); } //Oppure using (FileStream stream = new FileStream(@"C:\file.dat", FileMode.Open)) { struttura = (Struttura)binF.Deserialize(stream); } }

Luca

ciuky Profilo | Newbie

grazie luca per la risposta.

mi viene il dubbio però...così non creo un file con le descrizioni della struttura (ossia un vero e proprio xml)?

io nel file di output vorrei i dati in questo formato:

MioNomeMioCognomeMioIndirizzo

non so se mi sono spiegato?

ancora grazie! ;)

aiedail92 Profilo | Expert

>mi viene il dubbio però...così non creo un file con le descrizioni
>della struttura (ossia un vero e proprio xml)?

Sì, viene inserita anche la descrizione della struttura.

>io nel file di output vorrei i dati in questo formato:
>
>MioNomeMioCognomeMioIndirizzo

In tal caso devi per forza definire un formato specifico, ad esempio stabilendo che un certo carattere funge da separatore fra i tre campi (e quindi non può essere usato all'interno di ciascuno di essi), oppure specificando per ogni campo qual è la sua lunghezza (in modo da sapere dove finisce uno e dove inizia il successivo); in ogni caso comunque devi scriverti sia la funzione di salvataggio che quella di caricamento a mano...

Luca

ciuky Profilo | Newbie

certo.
infatti se noti la struttura che ho definito nel mio primo post ha campi dimensionati.
il mio problema non è tanto la lettura, piuttosto la scrittura della struttura nel file.

se ho capito bene la tua soluzione purtroppo non fa il caso mio, giusto?

aiedail92 Profilo | Expert

Allora puoi fare in questo modo (se ho intuito bene, devi usare delle stringhe stile C):

private void WriteCString(TextWriter writer, string var, int cSize) { //Se necessario, taglia la stringa if (var.Length >= cSize) var = var.Substring(0, cSize-1); //Scrive la stringa writer.Write(var); //Scrive i caratteri NULL di fill e terminazione delle stringhe C for (int i = var.Length; i < cSize; i++) { writer.Write('\0'); } } private void button1_Click(object sender, EventArgs e) { Struttura struttura = new Struttura(); struttura.nome = "MioNome"; struttura.cognome = "MioCognome"; struttura.indirizzo = "MioIndirizzo"; using (StreamWriter writer = new StreamWriter(@"C:\file.txt")) { WriteCString(writer, struttura.nome, 20); WriteCString(writer, struttura.cognome, 20); WriteCString(writer, struttura.indirizzo, 40); } }

Luca

ciuky Profilo | Newbie

no, niente...forse è colpa mia che non mi spiego bene.

per avere questo risultato mi basterebbe utilizzare lo streamwriter sw e utilizzare sw.writeline

quello che vorrei fare, considerando che la struttura non è così semplice come l'ho definita nell'esempio ma moooolto è complessa, è questo:

Avendo questa struttura:

Struttura struttura = new Struttura();
struttura.nome = "MioNome";
struttura.cognome = "MioCognome";
struttura.indirizzo = "MioIndirizzo";

vorrei poter scrivere sullo streamwriter direttamente "Struttura" così da avere nel mio file ascii il seguente risultato:

MinoNomeMioCognomeMioIndirizzo

senza dover concatenare stringhe o altre operazioni simili.





aiedail92 Profilo | Expert

Allora prova a vedere se questo fa al caso tuo:

Struttura struttura = new Struttura(); struttura.nome = "MioNome"; struttura.cognome = "MioCognome"; struttura.indirizzo = "MioIndirizzo"; int sz = Marshal.SizeOf(struttura); IntPtr mem = Marshal.AllocHGlobal(sz); Marshal.StructureToPtr(struttura, mem, false); using (FileStream stream = new FileStream(@"C:\file.txt", FileMode.Create)) { for (int i = 0; i < sz; i++) { stream.WriteByte(Marshal.ReadByte(mem, i)); } } Marshal.FreeHGlobal(mem);

Luca

ciuky Profilo | Newbie

LUca non mi odiare!!

ma così mi scrive un file in binario e non in ascii come vorrei.....:D

però credo che sia la strada buona.

o nO?

aiedail92 Profilo | Expert

Ciao, scusa se ti rispondo con tutto questo ritardo...

Ho pensato di sfruttare la reflection per ottenere tutti i campi della struttura e i relativi tipi e attributi (come MarshalAs) per avere tutte le informazioni per poter scrivere correttamente il campo.

È venuta fuori una cosa di questo genere:

Struttura struttura = new Struttura(); struttura.nome = "MioNome"; struttura.cognome = "MioCognome"; struttura.indirizzo = "MioIndirizzo"; //Ottiene tutti i campi della struttura FieldInfo[] fields = struttura.GetType().GetFields( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); //Crea il file e lo StreamWriter using (StreamWriter writer = new StreamWriter(@"C:\file.txt", false, Encoding.UTF8)) { //Cicla su tutti i campi foreach (FieldInfo field in fields) { //Ottiene il valore del campo object val = field.GetValue(struttura); //Comportamenti particolari per alcuni tipi: //string if (field.FieldType == typeof(string)) { string str = (string)val; //Ottiene l'attributo MarshalAs per sapere la dimensione fissa MarshalAsAttribute[] maattr = (MarshalAsAttribute[])field.GetCustomAttributes( typeof(MarshalAsAttribute), false); if (maattr.Length == 1) { //Taglia e padda la stringa per raggiungere la dimensione fissa str = str.PadRight(maattr[0].SizeConst, '\0').Substring(0, maattr[0].SizeConst); } //Scrive la stringa writer.Write(str); } ////altri comportamenti: //else if (field.FieldType = typeof(altroTipo)) //{ //} //Comportamento predefinito: else { writer.Write(val); } } }

Come puoi vedere per ora puoi scrivere le string senza problemi e penso anche tutti gli altri tipi fondamentali (int, char e così via), però per i tipi non base, se ti servono devi aggiungere manualmente le informazioni per la scrittura (c'è già lo scheletro, devi solo decommentarlo e aggiungere il codice personalizzato)

Spero che ora possa essere una buona base per il tuo lavoro, ma se hai altri dubbi o problemi chiedi pure

Luca
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5