1 Replies - 680 Views - Last Post: 28 June 2012 - 06:51 PM Rate Topic: -----

#1 johnwhile  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 28-November 11

Convert a file into a Struct's tree

Posted 26 June 2012 - 06:34 AM

Hi, I started to learn Csharp for creating plugins in games for large files that contain mostly 3d objects or generic. I have readed that using Struct instead Class is more speed and memory efficient, and it is this aspect in my case the most important part. These files are from 1.0 to 140.0 MB.

In attachment I included only the first reading part with a sample file that I know perfectly the format.

The problem is that by first test I got a time of 190ms for the first 600 bytes! My ideal case would be no more than a few ms ... My difficulty being new to this language and understand how to read efficiently and arrange in a large amount of Struct's hierarchy.
using System;
using System.Text;
using System.IO;
using System.Collections.Generic;


namespace MTW2Library
{
    #region Functions and Types
    public class Function
    {
        const int MAXLENGHT = 1000;
        public static string ReadGameString(BinaryReader file)
        {
            uint length = file.ReadUInt32();
            if (length == 0) return "";
            if (length < 0 | length > MAXLENGHT) { Console.WriteLine("ERROR : invalid String, exit for safety"); return null; }
            byte[] str = new byte[length];
            file.Read(str, 0, (int)length);
            return Encoding.UTF8.GetString(str);
        }
    }

    public struct sPoint3d
    {
        public float x;
        public float y;
        public float z;
        public void Point(float x, float y, float z) {this.x = x; this.y = y; this.z = z;}
        public override string ToString() { return (String.Format("[ {0:F2} {1:F2} {2:F2} ]", x, y, z));}
    }
    #endregion

    #region BoundingBoxClass
    public struct sBoundingBoxRow
    {
        public sPoint3d pivot;
        public sPoint3d pmin;
        public sPoint3d pmax;
        public Int32[] info;
        public override string ToString() { return ("p: " + pivot.ToString() + " min : " + pmin.ToString() + " max : " + pmax.ToString()); }
    }
    public struct sBoundingBoxTable
    {
        public int maxlevel;
        public int classid;
        public float BigFloat;
        public uint numbox;
        public sBoundingBoxRow[] bbox;

        public override string ToString()
        {
            string str = "level:" + maxlevel + " F:" + BigFloat + "\n";
            foreach (sBoundingBoxRow b in bbox){str+=b.ToString()+"\n";}
            return str;
        }
    }
    public class BoundingBoxRow
    {
        static bool flag = true;
        ~BoundingBoxRow() { flag = true; }
        public sBoundingBoxRow ReadBin(BinaryReader file)
        {
            // store data into struct
            sBoundingBoxRow BBR = new sBoundingBoxRow();
            if (flag) file.ReadUInt16(); // short0
            BBR.pivot.x = file.ReadSingle();
            BBR.pivot.y = file.ReadSingle();
            BBR.pivot.z = file.ReadSingle();
            BBR.info = new Int32[17];
            for (int i=0 ; i<17 ; BBR.info[i++] = file.ReadInt32());
            if (flag) file.ReadUInt16(); // short0
            BBR.pmax.x = file.ReadSingle();
            BBR.pmax.y = file.ReadSingle();
            BBR.pmax.z = file.ReadSingle();
            BBR.pmin.x = file.ReadSingle();
            BBR.pmin.y = file.ReadSingle();
            BBR.pmin.z = file.ReadSingle();
            // turn off the first utilize of this typeof data
            flag = false;
            return BBR;
        }
        public void WriteBin(BinaryWriter file) { }
        
    }
    public class BoundingBoxTable
    {
        static bool flag = true;
        ~BoundingBoxTable() { flag = true; }
        public sBoundingBoxTable ReadBin(BinaryReader file)
        {
            // store data into struct
            sBoundingBoxTable BBT = new sBoundingBoxTable();
            file.ReadInt32(); // int1
            if (flag) file.ReadUInt16(); // short0
            BBT.maxlevel = file.ReadInt32();
            BBT.classid = file.ReadInt32();
            BBT.BigFloat = file.ReadSingle();
            if (flag) file.ReadUInt16(); // short0
            BBT.numbox = file.ReadUInt32();
            if (flag) file.ReadUInt16(); // short0

            // check for safety , i must exit and stop reading
            if (BBT.numbox > 10000) {
                Console.WriteLine("ERROR : Bounding Box count too big, exit for safety");
                return BBT;}

            // store sub-data into struct
            BBT.bbox = new sBoundingBoxRow[BBT.numbox];
            BoundingBoxRow theClass = new BoundingBoxRow();
            for (int i = 0; i < BBT.numbox; BBT.bbox[i++] = theClass.ReadBin(file));

            // turn off the first utilize of this typeof data
            flag = false;
            return BBT;
        }
        public void WriteBin(BinaryWriter file, sBoundingBoxTable BBT) { }
    }
    #endregion


    #region Main WorldClass
    public struct sWorldBinary
    {
        public string headerStr;// = "serialization::archive";
        public byte[] headerBytes;// = { 3, 4, 4, 8, 1, 0, 0, 0, 0, 0, 11 };
        public sBoundingBoxTable boundingbox ;
        public override string ToString() { return (headerStr + "\n" + boundingbox.ToString()); }

    }
    public class WorldFormat
    {
        public string filename;
        public sWorldBinary data;
        
        public bool ReadBin(BinaryReader file)
        {
            // header of world file
            {
                Console.WriteLine("Leggo : " + filename);
                file.BaseStream.Seek(0, SeekOrigin.Begin);
                data.headerStr = Function.ReadGameString(file);
                if (data.headerStr == null) { return false; }
                data.headerBytes = new byte[11];
                file.Read(data.headerBytes, 0, 11);
            }

            // bounding box section
            {
                BoundingBoxTable theClass = new BoundingBoxTable();
                data.boundingbox = theClass.ReadBin(file);
            }//destruction

            // tableTwo section
            return true;
        }

    }
    #endregion
}




https://dl.dropbox.c...pplication1.rar

The main obstacle following tutorials are the non-standard data format, at first use of a struct there are a flag that defines the use of some short, I solved using a static flag and changing the value at the end.

Another obstacle is how to exit from reading process if you meet a wrong values​​, in fact, because the format is not exactly 100% completed, there may be cases of wrong readings, example struct's arrays size too big etc ...

I think it could be very useful to many beginners. Thanks in advance.

Is This A Good Question/Topic? 0
  • +

Replies To: Convert a file into a Struct's tree

#2 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 3575
  • View blog
  • Posts: 11,117
  • Joined: 05-May 12

Re: Convert a file into a Struct's tree

Posted 28 June 2012 - 06:51 PM

Did you use a profiler to get the number of 600ms, or did you setup a stopwatch around some lines of code? Did you make sure that that time did not include any overhead to open the file and fill the read buffers? Did you make sure that time is for Release code rather than Debug code? Did you make sure that time was the average of several runs outside the IDE?

C# is pretty efficient. Various experts claim speeds within 10% of pure native C++ code.

If you run into errors like unexpected inputs or "wild" values, you should throw an exception.

Anyway, the that static flag is such a hack. You really refactor the class into two classes with appropriate names to denote the two behaviors.

I think that one of the speed advantages that C/C++ maybe getting over your C# implementation is that C/C++ can read entire structures in one read versus your current reading on structure element at a time. File buffering should cover that difference though. The other advantage that C/C++ maybe getting is that it can memory map the entire datafile, and just overlay the structs on top of the memory. I'm not sure that you can do that with safe managed code. With unsafe managed code, it should be doable.

Also some interesting reading here about reading in C style structs into C# structs: http://www.codeproje...-Reading-with-C

This post has been edited by Skydiver: 28 June 2012 - 07:01 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1