Avatar billede idiotbarn Nybegynder
25. marts 2009 - 13:05 Der er 13 kommentarer og
2 løsninger

Hurtig gem/hent af fil

Hej
Jeg er igang med at rode med CUDA og skal i den forbindelse kopiere billeddata ned på graffikkortet. For det gøres effektivt, bruges en kopi funktion der tager start og længde af data.
Da den kopiere på denne måde kan jeg ikke rigtigt bruge Bitmap objektet da jeg så vil få hele "stride" og ikke kun dataen med.

Derfor har jeg lavet et nyt objekt som indeholder:

int height, width
byte[,] r,g,b

Jeg kommer til at gemme/hente en del, og skal derfor gerne ha minimeret tiden den bruger på det.
Jeg har gået ud fra den her artikkel, og lavet en enkelt tilføjelse:
http://www.codeproject.com/KB/cs/FastSerialization.aspx

Tilføjelsen består i at skrive et byte[,] foregår ved at skrive/læse én byte ad gangen.

Når jeg læser et billede via Bitmap tager det 7ms, mens hvis jeg læser objektet jeg har gemt, tager 37ms.

Hvad er den hurtigste måde at læse en fil fra harddisken? Det er hovedsageligt læsningen jeg er interesseret i.
Avatar billede aaberg Nybegynder
25. marts 2009 - 13:18 #1
Kan man se noget kode? Det er lidt svært, ud fra din beskrivelse alene, at komme med forbedringsforslag.

Men generelt: Det er ikke effektivt at læse en byte ad gangen. Læs hele billedet op i memory med en filestream, og behandle det derfra.

byte[] data;
using(FileStream stream = new FileStream("c:\mitbillede.png", FileMode.Open))
{
  data = new byte[stream.Length];

  stream.Read(data, 0, data.Length);
}
//Nu er data variablen fyldt op med data fra filen.
Avatar billede idiotbarn Nybegynder
25. marts 2009 - 13:34 #2
Jep... Har skrællet det overflødige fra, håber ikke jeg har fjernet for meget...

Nedenstående klasse har jeg taget fra codeproject, og tilføjet funktionen der skriver/læser byte[,]
public class SerializationWriter : BinaryWriter
{
...
        private SerializationWriter(Stream s) : base(s) { }

        /// <summary> Static method to initialise the writer with a suitable MemoryStream. </summary>

        public static SerializationWriter GetWriter()
        {
            MemoryStream ms = new MemoryStream(1024);
            return new SerializationWriter(ms);
        }

public void Write(byte[,] bytearr)
        {
            if (bytearr == null)
            {
                base.Write(0);
                base.Write(0);
                base.Write(-1);
            }
            else
            {
                int wx = bytearr.GetLength(0);
                int wy = bytearr.GetLength(1);

                base.Write(wx);
                base.Write(wy);
                for (int i = 0; i < wy; i++)
                {
                    for (int j = 0; j < wx; j++)
                    {
                        base.Write(bytearr[j, i]);
                    }
                }

            }
        }
        public void AddToInfo(SerializationInfo info)
        {
            byte[] b = ((MemoryStream)BaseStream).ToArray();
            info.AddValue("X", b, typeof(byte[]));
        }

...
}

public class SerializationReader : BinaryReader
{
...
private SerializationReader(Stream s) : base(s) { }
public static SerializationReader GetReader(SerializationInfo info)
        {
            byte[] byteArray = (byte[])info.GetValue("X", typeof(byte[]));
            MemoryStream ms = new MemoryStream(byteArray);
            return new SerializationReader(ms);
        }

public byte[,] ReadByteMultipleDimArray()
        {
            int lenx = ReadInt32();
            int leny = ReadInt32();
            if (lenx == 0 || leny == 0)
            {
                ReadInt32();
                return null;
            }
            byte[,] bytearr = new byte[lenx, leny];
            for (int i = 0; i < leny; i++)
            {
                for (int j = 0; j < lenx; j++)
                {
                    bytearr[j, i] = ReadByte();
                }
            }
            return bytearr;
        }
...
}

Klassen jeg henter/gemmer:

    [Serializable]
    public class SimpleImage : ISerializable
    {

public SimpleImage(SerializationInfo info, StreamingContext ctxt)
        {
            SerializationReader sr = SerializationReader.GetReader(info);
         
            Width = sr.ReadInt32();
            Height = sr.ReadInt32();
            r = sr.ReadByteMultipleDimArray();
            g = sr.ReadByteMultipleDimArray();
            b = sr.ReadByteMultipleDimArray();

        }
        public void Save(string Path, bool overwrite)
        {
            FileMode fm = FileMode.Create;
            if (!overwrite)
                fm = FileMode.CreateNew;

            FileStream fs = new FileStream(Path, fm);
            BinaryFormatter br = new BinaryFormatter();
            br.Serialize(fs, this);

            fs.Flush();
            fs.Close();
            fs.Dispose();
        }
        public static SimpleImage FromFile(string file)
        {
            FileStream fs = new FileStream(file, FileMode.Open);
            BinaryFormatter bf = new BinaryFormatter();
            SimpleImage sImg = (SimpleImage)bf.Deserialize(fs);
            fs.Close();
            fs.Dispose();
            return sImg;
        }
}
Avatar billede idiotbarn Nybegynder
25. marts 2009 - 13:36 #3
Klassen:
-  SerializationReader bruges til læsning
- SerializationWriter bruges til skrivning

constructoren :
public SimpleImage(SerializationInfo info, StreamingContext ctxt)
bliver kaldt ved deserializering
Avatar billede aaberg Nybegynder
25. marts 2009 - 14:33 #4
Jeg kan desværre ikke lige komme med forbedringsforslag. Jeg tror jeg måtte køre programmet i debug mode, for helt at forstå hvad der sker.

:-/
Avatar billede idiotbarn Nybegynder
25. marts 2009 - 14:50 #5
Den opretter egentligt bare en stream of læser et antal bytes fra den. Hvis man vil læse en int32 læser den 32bit frem o.s.v.

Men det kan være det er hurtigere at læse hele filen ind i hukommelsen for derefter at hive de forskellige ting ud fra den istedet for at gøre det lidt ad gangen...

Jeg prøver at lege lidt med filestream som du nævnte og se om jeg kan få nogen forbedringer...
Avatar billede idiotbarn Nybegynder
25. marts 2009 - 14:52 #6
aaaarh... doh... jeg kan se jeg havde glemt noget i koden SimpleImage der bruger ISerializable, implementere denne her metode
        #region ISerializable Members
       
  public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            SerializationWriter sw = SerializationWriter.GetWriter();

            sw.Write(Width);
            sw.Write(Height);
            sw.Write(r);
            sw.Write(g);
            sw.Write(b);
            sw.AddToInfo(info);
        }
#endregion
Avatar billede aaberg Nybegynder
25. marts 2009 - 15:52 #7
Det der ofte tager lang tid, når man læser og skriver på disken, er når der bliver kørt mange små operationer. Det tager eksempeltvis også meget længere tid at kopiere mange små filer, end 1 stor.

I denne metode:
        public static SimpleImage FromFile(string file)
        {
            FileStream fs = new FileStream(file, FileMode.Open);
            BinaryFormatter bf = new BinaryFormatter();
            SimpleImage sImg = (SimpleImage)bf.Deserialize(fs);
            fs.Close();
            fs.Dispose();
            return sImg;
        }

...giver du en FileStream som argument til Deserialize metoden på din BinaryFormatter. Prøv i stedet at læse hele indholdet fra filen ind i en MemoryStream, og brug denne som argument.

Jeg kan ikke lige overskue om det samme kan gøres flere steder fra koden.
Avatar billede arne_v Ekspert
26. marts 2009 - 02:38 #8
Jeg ville snarere prøve at wrappe Stream i en BufferedStream for disk IO.
Avatar billede arne_v Ekspert
26. marts 2009 - 02:40 #9
cc>

byte[] data;
using(FileStream stream = new FileStream("c:\mitbillede.png", FileMode.Open))
{
  data = new byte[stream.Length];

  stream.Read(data, 0, data.Length);
}
//Nu er data variablen fyldt op med data fra filen.

er ofte set, men man skal læse det med småt i docs for Read.

"An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached."

while løkke er obligatorisk.
Avatar billede aaberg Nybegynder
26. marts 2009 - 11:56 #10
Hej arne_v. Jeg har faktisk en gang løbet i problemer, netop med det du pointerer. Men det var med en NetworkStream. Jeg har aldrig hørt eller oplevet at en Filestream ikke returnerer hele filen.

Men klart! man bør jo gøre det rigtig fra starten, at putte det ind i en while løkke skader jo i hvert fald ikke, så længe man sørger for at bufferen er forholdsvis stor.
Avatar billede arne_v Ekspert
26. marts 2009 - 14:04 #11
Jeg har heller aldrig oplevet problemer med on disk filer, men docs er ret klar - man kan ikke regne med det.

Og man kan lave bufferen lige saa stor som filen og stadig bruge while. Virker det i et genneloeb saa fint hvis ikke saa ogsaa fint.
Avatar billede idiotbarn Nybegynder
27. marts 2009 - 09:27 #12
Tak for svarene, jeg vil prøve at lege lidt med de to forslag, og se hvad der er hurtigst.

Jeg står midt i en flytning, så der kan godt gå et par dage før internet o.s.v er på plads, men vender snart tilbage. God weekend :)
Avatar billede idiotbarn Nybegynder
24. februar 2011 - 19:11 #13
Fik aldrig vendt tilbage, sorry. Ligger i et svar, så acceptere jeg
Avatar billede aaberg Nybegynder
24. februar 2011 - 19:31 #14
Svar :)
Avatar billede arne_v Ekspert
24. februar 2011 - 19:39 #15
ok
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