Avatar billede haolan Nybegynder
05. januar 2007 - 12:14 Der 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);
            }
        }
Avatar billede haolan Nybegynder
05. januar 2007 - 12:18 #1
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
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 12:28 #2
er det ikke fordi din brugerCollection.GetBruger() - metode altid returnerer den første bruger i listen?
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 12:29 #3
du kunne eventuelt udvide metoden således at den tager en int parameter og så retunerer brugeren på den plads i listen...
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 12:31 #4
...så vil du selvfølgelig være nødt til at oprette en "tæller" før "do" og opdatere denne når du er færdig inde i "do"-delen.
Avatar billede haolan Nybegynder
05. januar 2007 - 12:32 #5
Den virkede faktisk før jeg fulgte dette spørgsmål:
http://www.eksperten.dk/spm/754085

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);
        }
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 12:33 #6
i stil med det her:

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);
}
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 12:34 #7
prøv at kigge i den fil du skriver ud er de to brugere ens i den?
Avatar billede haolan Nybegynder
05. januar 2007 - 12:36 #8
Når jeg bruger din løsning fejler min iterator..

Den skriver:
Indekset lå uden for området. Det må ikke være negativt og skal være mindre end størrelsen på samlingen.
Parameternavn: index
Avatar billede haolan Nybegynder
05. januar 2007 - 12:44 #9
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.
Avatar billede haolan Nybegynder
05. januar 2007 - 12:46 #10
Har lige lavet et nyt forsøg..

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
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 12:53 #11
kan du prøve at vise din BrugerCollection klasse...
Avatar billede haolan Nybegynder
05. januar 2007 - 13:44 #12
Min bruger collection ser sådan ud:

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);
        }
    }
}
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 14:17 #13
Hvad med at ændre din do - while struktur til:

ArrayList brugere = brugerCollection.GetAllUser();

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:

cbVælgBruger.DataSource = brugere;

(går udfra at cbVælgBruger er en comboBox)
Avatar billede haolan Nybegynder
05. januar 2007 - 14:38 #14
hmm den viser stadig kun den første bruger :S
og er vel nødt til at køre do while løkken alligevel for at få added brugere til min brugerCollection
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 14:58 #15
ligger brugerne ikke allerede i den brugerCollection du henter dem ind fra disken?
Avatar billede haolan Nybegynder
05. januar 2007 - 15:12 #16
hmm jo har du vel ret i..

men den udskriver stadig kun den første fra filen :S
Avatar billede haolan Nybegynder
05. januar 2007 - 15:13 #17
Men har lige lagt mærke til at den laver en header for hver bruger der bliver gemt i filen..

Det burde den vel ikke?
Avatar billede haolan Nybegynder
05. januar 2007 - 16:16 #18
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);

            while(brugerCollection.TestBrugerNr(testnr) == false)
            {
                testnr = rnd.Next(0, 999);
            }
            brugernr = testnr;

            //KALD NAVN IND FRA BRUGEREN
            navn = txtFornavn.Text + " " + txtEfternavn.Text;

            //OPRET BRUGEROBJEKT
            bruger = brugerCollection.OpretBruger(brugernr);
            bruger.SetNavn(navn);

            MessageBox.Show("Bruger oprettet med ID: #" + brugernr);

            //SKAB FIL FOR SKRIVNING
            FileStream filestream = new FileStream(FILNAVN, FileMode.Create, FileAccess.Write);

            //TILKNYT BINARY-FORMATER TIL FILESTREAM
            BinaryFormatter binFormatter = new BinaryFormatter();

            //SERIALISÉR BRUGERCOLLECTION TIL FILESTREAM
            binFormatter.Serialize(filestream, brugerCollection);

            //LUK FILESTREAM
            filestream.Close();

            //OPDATÉR BRUGERLISTE
            OpdaterBrugerListe();
        }
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 21:21 #19
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();
            }
        }

        /// <summary>
        /// Skriver brugerlisten
        /// </summary>
        /// <param name="filmListe"></param>
        public void gemFilm(ArrayList brugerListe)
        {
            file = data + "\\Brugere.brugerdata";
            brugerListe.Sort();
            FileStream outFile = File.Create(file);
            bf.Serialize(outFile, brugerListe);
            outFile.Close();
        }
        #endregion
        }
}

Når du så skal lave en ny kan du bare hente listen ind, lave et bruger objekt, smide det ind i listen og gemme det igen.

I din bruger klasse kan du så som jeg nævnte tidligere override Tostring metoden således:

public override string ToString()
{
    return navn + " (" + brugernr.ToString() + ")";
}

og når du skal vise dem i comboboxen gør du bare følgende:

GemHent gh = new GemHent();
ArrayList brugere = gh.hentBrugere();
cbVælgBruger.DataSource = brugere;

NB. for at anvende sort skal du indsætte denne metode i din bruger klasse for at definere hvad der skal sorteres på:

public int CompareTo(object o)
{
    Bruger bruger = (Bruger)b;
    return navn.CompareTo(b.getNavn());
}

Hvis det alstå er navn du vil sortere på.

Håber det giver mening ellers må du sige til.
Avatar billede mikkel_sommer Nybegynder
05. januar 2007 - 21:22 #20
* compareTo skal selvfølgelig være således:

public int CompareTo(object b)
{
    Bruger bruger = (Bruger)b;
    return navn.CompareTo(b.getNavn());
}
Avatar billede haolan Nybegynder
07. januar 2007 - 16:01 #21
Hvad bruger du Istart og ILen til i din kunstruktør?
Avatar billede haolan Nybegynder
07. januar 2007 - 16:32 #22
Den der compareTo virker ikke :S

        public int CompareTo(object b)
        {
            Bruger bruger = (Bruger)b;
            return navn.CompareTo(b.GetNavn());
        }
Den kan ikke finde GetNavn i brugerklassen :S

Og hvis jeg udkommentere sorteringen, kan jeg kun tilføje et brugerobjekt.. Hvis jeg tilføjer flere forsvinder alle brugere :S
Avatar billede haolan Nybegynder
07. januar 2007 - 17:20 #23
skal også lige sige at i min comboboks bliver kun brugernummeret vist.. :S navnet bliver ignoreret...
Avatar billede mikkel_sommer Nybegynder
08. januar 2007 - 08:43 #24
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).

Prøv med: return "" + navn + " (" + brugernr.ToString() + ")";
Avatar billede haolan Nybegynder
08. januar 2007 - 20:31 #25
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..
Avatar billede mikkel_sommer Nybegynder
09. januar 2007 - 08:56 #26
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;
Avatar billede haolan Nybegynder
10. januar 2007 - 12:17 #27
Har godt nok brugt proberties før og vil da klart anvende dem igen :)

takker for hjælpen..
Avatar billede mikkel_sommer Nybegynder
10. januar 2007 - 12:39 #28
Velbekommen :)
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester