05. januar 2007 - 12:14Der er
27 kommentarer og 1 løsning
Kald af flere brugere fra en arraylist i BinaryFileStream
Hej igen eksperter :)
Har et lille problem med at få min StreamReader til at udskrive alle mine brugere jeg gemmer i min binære fil.
Den udskriver kun 1 fra filen og resten ignorerer den..
Går ud fra det bare er en af de små bitte skodfejl man kan bande over i en halv time efter man har fundet løsningen :P
Her er den funktion der kalder mine brugere ud:
public void OpdaterBrugerListe() { //INDLÆS FORNØDNE KLASSER BrugerCollection brugerCollection = new BrugerCollection(); Bruger bruger; ArrayList brugere = new ArrayList();
//ÅBEN FIL FOR LÆSNING FileStream fileStream = new FileStream(FILNAVN, FileMode.Open, FileAccess.Read);
//TILKNYT BINARY-FORMATER TIL FILESTREAM BinaryFormatter binFormatter = new BinaryFormatter();
//DESERIALISÉR FILESTREAM TIL BRUGERCOLLECTIOn brugerCollection = (BrugerCollection)binFormatter.Deserialize(fileStream);
//LUK FILESTREAM fileStream.Close();
//GENNEMLØB ITERATOR OG INDSÆT BRUGERE I COMBOBOKSEN string navn; int brugernr; if (brugerCollection.Foerste()) { do { bruger = brugerCollection.GetBruger(); navn = bruger.GetNavn(); brugernr = bruger.GetBrugerNr(); brugere.Add(bruger); cbVælgBruger.Items.Add(navn + " (" + brugernr.ToString() + ")"); } while (brugerCollection.Naeste()); brugerCollection.SaveUsers(brugere); } }
Kan lige sige at når jeg opretter en ny bruger bliver den gemt rigtigt nok i filen, men i min comboboks (cbVælgBruger) gentager den bare sig selv, så det første navn i array vises to gange :S
I den forbindelse lavede jeg create om til append når jeg ligger brugere ind i filen.
Min iterator der gennemløber brugerne ser sådan ud:
//POST: ITERATOR NULSTILLES (DVS. PEGER PÅ FØRSTE BRUGER) // -- RETURNERER FALSE HVIS DER IKKE ER NOGEN BRUGERE, ELLER TRUE public bool Foerste() { aktuelBrugerIdx = 0; return (brugere.Count > 0); }
//POST: AKTUEL VARE (DEN SOM ITERATOREN PEGER PÅ) RETURNERES public Bruger GetBruger() { return (Bruger)(brugere[aktuelBrugerIdx]); }
//POST: PEGER PÅ NÆSTE BRUGER HVIS DER ER FLERE // - OG RETURNERER TRUE, ELLERS FALSE public bool Naeste() { aktuelBrugerIdx++; return (aktuelBrugerIdx < brugere.Count); }
if (brugerCollection.Foerste()) { int i = 0; do { bruger = brugerCollection.GetBruger(i); navn = bruger.GetNavn(); brugernr = bruger.GetBrugerNr(); brugere.Add(bruger); cbVælgBruger.Items.Add(navn + " (" + brugernr.ToString() + ")"); i++; } while (brugerCollection.Naeste()); brugerCollection.SaveUsers(brugere); }
I filen er der 4 brugere.. Når jeg åbner programmet vises kun den første.. Hvis jeg opretter en ny bruger, gemmer den i filen ganske fint.. Men i comboboksen vises den første så to gange istedet.
Jeg kører jo OpdaterBrugerListe(); Hver gang jeg opretter en ny bruger.. Hvis jeg skriver: OpdaterBrugerListe(); OpdaterBrugerListe(); OpdaterBrugerListe();
Vises den første bruger fra filen 4 gange i stedet :S
using System; using System.Collections.Generic; using System.Text; using System.Collections;
namespace Sportal { [Serializable] //SØRGER FOR AT BRUGERCOLLECTION KAN SERIALISERES class BrugerCollection { private ArrayList brugere;
[NonSerialized] //SØRGER FOR AT NÆSTE LINIE IKKE MEDTAGES I SERIALISERINGEN private int aktuelBrugerIdx;
public BrugerCollection() { brugere = new ArrayList(); aktuelBrugerIdx = 0; }
//GEM BRUGERNE I COLLECTION public void SaveUsers(ArrayList users) { brugere = users; }
//HENT ALLE BRUGERE TIL GENNEMLØB public ArrayList GetAllUsers() { return brugere; }
public bool TestBrugerNr(int testnr) { int x = 0; foreach (Bruger b in brugere) { if (b.GetBrugerNr() == testnr) x++; } if (x > 0) return false; else return true;
}
//PRE: BRUGERNR FINDES IKKE I NOGEN ANDRE BRUGERE //POST: BRUGEROBJEKT OPRETTET OG RETURNERET public Bruger OpretBruger(int brugernr) { Bruger bruger = new Bruger(brugernr); brugere.Add(bruger); return bruger; }
//PRE: BRUGERNR FINDES I BRUGERE //POST: INDEX I BRUGERE FOR BRUGER MED BRUGERNR RETURNERET private int GetBrugerIdx(int brugernr) { int i; for (i = 0; i < brugere.Count; i++) { if (brugernr == ((Bruger)brugere[i]).GetBrugerNr()) break; } return i; }
//PRE: BRUGERNR FINDES I BRUGERE //POST: BRUGER MED BRUGERNR SLETTET FRA BRUGERE public void SletBruger(int brugernr) { int index; index = GetBrugerIdx(brugernr); brugere.RemoveAt(index); }
//PRE: BRUGERNR FINDES I BRUGERE //POST: BRUGER MED BRUGERNR RETURNERET public Bruger GetBruger(int brugernr) { int index; index = GetBrugerIdx(brugernr); return (Bruger)(brugere[index]); }
//ITERATOR-METODER (GENNEMLØB AF BRUGERE)
//POST: ITERATOR NULSTILLES (DVS. PEGER PÅ FØRSTE BRUGER) // -- RETURNERER FALSE HVIS DER IKKE ER NOGEN BRUGERE, ELLER TRUE public bool Foerste() { aktuelBrugerIdx = 0; return (brugere.Count > 0); }
//POST: AKTUEL VARE (DEN SOM ITERATOREN PEGER PÅ) RETURNERES public Bruger GetBruger() { return (Bruger)(brugere[aktuelBrugerIdx]); }
//POST: PEGER PÅ NÆSTE BRUGER HVIS DER ER FLERE // - OG RETURNERER TRUE, ELLERS FALSE public bool Naeste() { aktuelBrugerIdx++; return (aktuelBrugerIdx < brugere.Count); } } }
Hvis du så i din bruger klasse overrider ToString metoden til at returnere en streng formateret som du gerne vil have den vist i listen kan du nøjes med:
Det ville virke hvis jeg brugte create istedet for append er jeg ret sikker på.. Problemet er når jeg creater ell. overskriver min fil finder den kun den senest oprettede bruger, fordi den bliver kaldt ind når jeg gemmer..
Jeg tror problemet opstår ved at jeg bruger new BrugerCollection inden jeg opretter brugeren i systemet..
Funktionen for oprettelse ser sådan ud: private void btnOpretBruger_Click(object sender, EventArgs e) { //KALD DE FORNØDNE KLASSER BrugerCollection brugerCollection; Bruger bruger; brugerCollection = new BrugerCollection(); //Her burde den kalde den eksisterende liste ind istedet for at oprette en ny.. Men hvordan??
//INDLÆS ATTRIBUTTER string navn; int brugernr;
//LAV ET BRUGERNUMMER Random rnd = new Random(DateTime.Now.Millisecond); int testnr; testnr = rnd.Next(0,999);
hvis jeg var dig ville jeg droppe den der brugerCollection og bare køre med et arraylist og så lave to metoder, en til at hente en arrayliste af brugere ind fra disken og en til at gemme en.
Jeg har et eksempel hvor jeg har lagt sådanne to metoder i en klasse for sig, det er godt nok til film men navnene kan du jo bare ændre efter behag:
using System; using System.IO; using System.Text; using System.Data; using System.Collections; using System.Runtime.Serialization.Formatters.Binary;
namespace FilmKartotek { /// <summary> /// GemHent klassen indeholder alle metoder som læser og skriver til disken /// </summary> [Serializable] public class GemHent { #region Variabler string basefolder = Environment.CurrentDirectory; string file = string.Empty; string data = string.Empty; BinaryFormatter bf = new BinaryFormatter(); #endregion
#region Constructor /// <summary> /// GemHent klassens konstruktør /// </summary> public GemHent() { basefolder = Environment.CurrentDirectory; data = basefolder + "\\Data"; int iStart = basefolder.LastIndexOf(@"\"); int iLen = basefolder.Length - iStart; if (!System.IO.Directory.Exists(data)) { System.IO.Directory.CreateDirectory(data); } } #endregion
#region Brugere /// <summary> /// Henter brugerlisten fra disken /// </summary> /// <returns></returns> public ArrayList hentBrugere() { ArrayList brugere = new ArrayList(); file = data + "\\Brugere.brugerdata"; try { FileStream inFile = File.OpenRead(file); brugere = (ArrayList)bf.Deserialize(inFile); inFile.Close(); brugere.Sort(); return brugere; } catch(SystemException) { return new ArrayList(); } }
jamen du har da en GetNavn() i din bruger klasse ikke?
Istart og ILen er noget gammelt noget jeg ikke har fået fjernet, brugte det i sin tid til at finde den sidste del af stien(det som kom efter sidste bagslash).
Fandt ud af at jeg bare kunne smide brugerCollection = new BrugerCollection(); uden for metoden, så var der ikke noget problem i hverken at hente eller gemme data :)
Men vil lige rode lidt i at bruge din Compare metode alligevel.. :) den ville være nice..
Du kan med fordel lave properties i stedet for at have get og set metoder for din bruger klasses attributter, det ville gøre tilgangen i eksempelves compare metoden lidt lettere.
Ved ikke om du har arbejdet med properties før men det kunne se således ud:
private string fornavn, efternavn, tlf;
public string Fornavn { get {return fornavn;} set {fornavn = value;} }
public string Efternavn { get {return efternavn;} set {efternavn = value;} }
public string Tlf { get {return tlf;} set {tlf = value;} }
I dette tilfælde ville du så i din kode kunne gøre således for at få fat i værdierne:
Person p = new Person("Mikkel", "Sommer", "12345678"); string navn = p.Fornavn;
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.