2.1.7 电子海图系统解析及开发 海图解析 -- 读取ISO/IEC 8211文件

通过上文的内容,已经了解到S-57文件符合ISO/IEC 8211作为其数据封装标准。一个文件已分成若干个逻辑记录(LR),每一个LR有三个基本元素头标区(对应类S57Leader)、目录区(对应类S57Directory)和字段区,其中文件中的第一个LR为DDR(存储文件中实际数据的描述和逻辑结构,对应类S57DDR),其他的LR为DR(存储文件中的实际数据,对应类S57DR)。

S-57文件封装标准

依照上图,新建类Iso8211File解析S-57文件,主要包含一个S57DDR字段和一个List列表。由于DDR和DR的头标区与目录区格式一致,因此将字段S57Leader和字段S57Directory放到类S57LR中,让DDR和DR继承自LR。DDR的字段区包含字段控制字段数据描述字段,因此类S57DDR还包含字段S57FieldControlField和字段S57DataDescriptiveFields。DR的字段区解析逻辑与DDR不一样,因此类S57DR还包含字段S57FieldArea。最后得到如下代码结构:

    public class S57LR
    {
        public S57Leader Leader;                                //头标区
        public S57Directory Directory;                          //目录区
    }

    public class S57DDR : S57LR
    {
        public S57FieldControlField FieldControlField;          //字段区 字段控制字段
        public S57DataDescriptiveFields DataDescriptiveFields;  //字段区 数据描述字段
    }

    public class S57DR : S57LR
    {
        public S57FieldArea FieldArea;                          //字段区 字段控制字段
    }

    public class Iso8211File
    {
        public S57DDR DDR;
        public List DRs;
    }

接下来,完成Iso8211File的构造函数,输入参数为S-57文件的路径。首先解析出文件的DDR头标区、目录录、字段控制字段和数据描述字段,利用其信息,循环解析出其他DR,具体代码如下:

        //构造函数,传入S57文件路径
        public Iso8211File(string filePath)
        {
            DDR = new S57DDR();
            DRs = new List();

            //加载S57文件,得到二进制数据
            BytesHelper.Load(filePath);

            //DDR 头标区
            DDR.Leader = new S57Leader();

            //DDR 目录区
            DDR.Directory = new S57Directory(DDR.Leader);

            //DDR 字段区
            //DDR 字段控制字段
            var tag0000 = DDR.Directory.Items[0];
            DDR.FieldControlField = new S57FieldControlField(tag0000.FieldLength, DDR.Leader.FieldTagSize);

            //DDR 数据描述字段
            DDR.DataDescriptiveFields = new S57DataDescriptiveFields(DDR.Directory);

            //循环解析DR
            while (BytesHelper.Position < BytesHelper.ENCBytes.Length - 2)
            {
                var dr = new S57DR();

                //DR 头标区
                dr.Leader = new S57Leader();

                //DR 目录区
                dr.Directory = new S57Directory(dr.Leader);

                //DR 字段区
                dr.FieldArea = new S57FieldArea(dr.Directory, DDR.DataDescriptiveFields);

                DRs.Add(dr);
            }
        }

最后验证结果:

            var reader = new Iso8211File("..\\US4AK7IM.000");
            var dl = reader.DDR.Leader;
            var header = dl.RecordLength.ToString() + dl.FieldControlString
                + dl.FieldAreaBaseAddress.ToString() + dl.ExCharacterSetIndicator
                + dl.FieldLengthSize.ToString() + dl.FieldPositionSize.ToString()
                + dl.Reserved.ToString() + dl.FieldTagSize.ToString();
            Console.WriteLine("DDR头标区:" + header);

            Console.WriteLine("DDR目录区:");
            foreach (var di in reader.DDR.Directory.Items)
            {
                Console.WriteLine($"标签:{di.Tag}\t长度:{di.FieldLength}\t位置:{di.FieldPosition}");
            }

            Console.WriteLine("DR的个数为:" + reader.DRs.Count);
S-57文件解析结果

至此,S-57文件的解析部分已全部完成了,我们可以清楚的掌握文件中的每一个标签,各标签下都有什么属性,各属性的值是什么。但不同标签对应真实世界实体的什么?不同的属性代表什么含义?各属性的值又能说明什么?需要对S-57标准的进一步解读。

你可能感兴趣的:(2.1.7 电子海图系统解析及开发 海图解析 -- 读取ISO/IEC 8211文件)