![]() |
AW: Datei mit dynamischen Array einlesen
Zitat:
aber da sind sie ja nicht die einzigen. @lagalex Ich traue im allgemeinen nur dem Hexdump, den ich selber mache, darum Du bist Dir sicher, daß Du auch wirklich am Offset 100 startest? Wenn da eine Verschiebung um 3 Byte stattgefunden hat, dann wäre das eine Erklärung für den Little/Big-Endian Wechsel. (und Dokumentationspapier ist geduldig, sehr geduldig...) Gruß K-H |
AW: Datei mit dynamischen Array einlesen
Ja das weiß ich, deswegen auch der Befehl SwapBytes für die BigEndians.
TStream.Position zeigt mir 100 bevor ich den ominösen RecordHeader einlese. Das was ich dann bekomme ist weder Big noch Little, hab alles probiert, mit und ohne SwapBytes. Kann vielleicht der Fehler bei den Packed Records liegen? Oder ist das in der Dokumentation beschriebene Integer evtl unsigned, habs aber auch mit LongWord und Cardinal probiert, keine Veränderung. Irgendwie steh ich auf der Leitung :-/ |
AW: Datei mit dynamischen Array einlesen
:wall: Meine Güte! Ein typischer Fall von "Wald vor lauter Bäumen" nicht sehen... :pale:
es war das repeat .. until, hab wohl übers Ziel hinausgeschossen... Dank an alle!! |
AW: Datei mit dynamischen Array einlesen
Nein, war es nicht. Das ist falsch:
Delphi-Quellcode:
Und hier meine "verbesserte" Version:
SetLength(PLContent.Parts, PLHead.NumParts);
SetLength(PLContent.Points, PLHead.NumPoints); Strom.ReadBuffer(PLContent,SizeOf(PLContent));
Delphi-Quellcode:
unit shapefiles;
interface uses Classes, SysUtils; type TSHPFileHeader = packed record // Big Endian FileCode : LongInt; Unused1, Unused2, Unused3, Unused4, Unused5 : LongInt; FileLen : LongInt; // Little Endian Version : LongInt; ShapeType: LongInt; Xmin : Double; Ymin : Double; Xmax : Double; Ymax : Double; Zmin : Double; Zmax : Double; Mmin : Double; Mmax : Double; end; TRecordHeader = packed record Nummer: LongInt; // Big Endian Laenge: LongInt; // Big Endian end; TBox = Array[0..3] of Double; TPunkt = packed record ID : LongInt; X : Double; Y : Double; end; TPunktXY = record X, Y : Double; end; TPolyLine = record ShapeType : LongInt; Box : TBox; NumParts : LongInt; NumPoints : LongInt; Parts : Array Of LongInt; Points : Array Of TPunktXY; end; TPolyHeader = packed record Shapetype : LongInt; Box : TBox; NumParts : LongInt; NumPoints : LongInt; end; TPolyContent = packed record Parts : Array of LongInt; Points : Array of TPunktXY; end; TShapefile = class protected FErrMsg: string; FError : Boolean; procedure ReadFromStream(Stream : TFileStream); public FileHeader : TSHPFileHeader; PLHead : TPolyHeader; PLContent : TPolyContent; Punkte : array Of TPunkt; PolyLinien : array of TPolyLine; procedure AddPoint (ID : LongInt; X, Y : Double); procedure AddPLPart (ID : LongInt; zahl : LongInt); procedure LoadSHP(const AFilename : string); property ErrMsg: string read FErrMsg; property Error: Boolean read FError; end; const shpNullShape = 0; shpPoint = 1; shpPolyLine = 3; shpPolygon = 5; shpMultiPoint = 8; shpPointZ = 11; shpPolyLineZ = 13; shpPolygonZ = 15; shpMultiPointZ = 18; shpPointM = 21; shpPolyLineM = 23; shpPolygonM = 25; shpMultiPointM = 28; shpMultiPatch = 31; sizeHeader = 100; implementation function ChangeEndian32(AValue: LongWord): LongWord; register; asm bswap EAX // konvertiert Reienfolge der Byte end; procedure TShapeFile.AddPoint(ID: LongInt; X, Y: Double); begin SetLength(Punkte,Length(Punkte)+1); Punkte[High(Punkte)].ID := ID; Punkte[High(Punkte)].X := X; Punkte[High(Punkte)].Y := Y; end; procedure TShapeFile.AddPLPart (ID : LongInt; zahl : LongInt); begin //if (High(PolyLinien)<ID) then SetLength(PolyLinien,ID+1); // end; procedure TShapefile.ReadFromStream(Stream : TFileStream); var In_Punkt : TPunkt; index : integer; RecordHeader : TRecordHeader; begin FError := False; FErrmsg := ''; // Lies den Header des Shapefiles ein try Stream.ReadBuffer(FileHeader,SizeOf(FileHeader)); except FError := True; FErrmsg := 'Kein gültiges ESRI-Shapefile!'; Exit; end; // Big Endian in Little Endian umwandeln FileHeader.FileCode := ChangeEndian32(FileHeader.FileCode); FileHeader.FileLen := ChangeEndian32(FileHeader.FileLen); // Records einlesen Index := 0; try repeat index:=index+1; Stream.ReadBuffer(RecordHeader, SizeOf(RecordHeader)); // Big Endian RecordHeader.Nummer := ChangeEndian32(RecordHeader.Nummer); RecordHeader.Laenge := ChangeEndian32(RecordHeader.Laenge); case FileHeader.ShapeType of 1: // Punkt - Shapefile begin Stream.Read(In_Punkt, SizeOf(In_Punkt)); AddPoint(RecordHeader.Nummer, In_Punkt.X, In_Punkt.Y); end; 3: // PolyLine - Shapefile begin SetLength(PolyLinien, index); Stream.ReadBuffer(PLHead, SizeOf(PLHead)); SetLength(PLContent.Parts, PLHead.NumParts); SetLength(PLContent.Points, PLHead.NumPoints); Stream.ReadBuffer(PLContent.Parts[0], SizeOf(PLContent.Parts[0]) * PLHead.NumParts); Stream.ReadBuffer(PLContent.Points[0], SizeOf(PLContent.Points[0]) * PLHead.NumPoints); end; end; until (Stream.Position >= (FileHeader.FileLen * 2)); // da Filesize in Word = // 16-Bit = 2 Bytes angegeben wird except FError := True; FErrmsg := 'Fehler beim Einlesen der einzelnen Elemente bei ID : ' + IntToStr(RecordHeader.Nummer); Exit; end; end; procedure TShapefile.LoadSHP(const AFilename : string); var Stream : TFileStream; begin Stream := TFileStream.Create(AFilename, fmOpenRead); try ReadFromStream(Stream); finally Stream.Free; end; end; end. |
AW: Datei mit dynamischen Array einlesen
Hallo Blup,
Vielen Dank für Deine Antwort und Deine Mühe - ja, Deine ist wohl die elegantere Version als meine, werds mir genauer ansehen und dazulernen... Ich habs jetzt so lösen können :
Delphi-Quellcode:
unit shapefiles;
{$mode objfpc}{$H+} interface uses Classes, SysUtils; type TSHPFileHeader = packed record // Big Endian FileCode : LongInt; Unused1, Unused2, Unused3, Unused4, Unused5 : LongInt; FileLen : LongInt; // Little Endian Version : LongInt; ShapeType: LongInt; Xmin : Double; Ymin : Double; Xmax : Double; Ymax : Double; Zmin : Double; Zmax : Double; Mmin : Double; Mmax : Double; end; type TRecordHeader = packed record Nummer : LongInt; // Big Endian Laenge : LongInt; // Big Endian end; type TBox = Array[0..3] of Double; type TPunkt = packed record ID : LongInt; X : Double; Y : Double; end; type TPunktXY = record X, Y : Double; end; type TPolyLine = record ShapeType : LongInt; Box : TBox; NumParts : LongInt; NumPoints : LongInt; Parts : Array Of LongInt; Points : Array Of TPunktXY; end; type TPolyHeader = packed record Shapetype : LongInt; Box : TBox; NumParts : LongInt; NumPoints : LongInt; end; type TPolyContent = packed record Parts : Array of LongInt; Points : Array of TPunktXY; end; type TShapefile = class public FileHeader : TSHPFileHeader; RecordHeader : TRecordHeader; PLHead : TPolyHeader; PLContent : TPolyContent; error : boolean; errmsg : String; Punkte : Array Of TPunkt; PolyLinien : Array of TPolyLine; constructor Create; procedure AddPoint (ID : LongInt; X, Y : Double); procedure LoadSHP(datnam : string); end; const shpNullShape = 0; shpPoint = 1; shpPolyLine = 3; shpPolygon = 5; shpMultiPoint = 8; shpPointZ = 11; shpPolyLineZ = 13; shpPolygonZ = 15; shpMultiPointZ = 18; shpPointM = 21; shpPolyLineM = 23; shpPolygonM = 25; shpMultiPointM = 28; shpMultiPatch = 31; sizeHeader = 100; var wo : integer; procedure SwapBytes(Var Bytes; Len : Integer); implementation constructor TShapeFile.Create; begin inherited; error:=false; // Dynamische Arrays auf 0 setzen SetLength(Punkte,0); SetLength(PolyLinien,0); end; procedure TShapeFile.AddPoint(ID : LongInt; X, Y : Double); begin SetLength(Punkte,Length(Punkte)+1); Punkte[High(Punkte)].ID:=ID; Punkte[High(Punkte)].X:=X; Punkte[High(Punkte)].Y:=Y; end; procedure TShapefile.LoadSHP(datnam : string); var Strom : TFileStream; In_Punkt : TPunkt; index : integer; i,j : integer; begin // Lies den Header des Shapefiles ein try Strom:=TFileStream.Create(datnam,fmOpenRead); Strom.ReadBuffer(FileHeader,SizeOf(FileHeader)); except error:=true; errmsg:='Kein gültiges ESRI-Shapefile!'; Strom.Free; exit; end; // Big Endian in Little Endian umwandeln SwapBytes(FileHeader.FileCode,SizeOf(FileHeader.FileCode)); SwapBytes(FileHeader.FileLen,SizeOf(FileHeader.FileLen)); // Records einlesen index:=0; try repeat index:=index+1; Strom.ReadBuffer(RecordHeader, 8); // Big Endian SwapBytes(RecordHeader.Nummer, 4); SwapBytes(RecordHeader.Laenge, 4); case FileHeader.ShapeType of 1 : begin // Punkt - Shapefile Strom.Read(In_Punkt,SizeOf(In_Punkt)); AddPoint(RecordHeader.Nummer, In_Punkt.X, In_Punkt.Y); end; 3 : begin // PolyLine - Shapefile SetLength(PolyLinien,index); Strom.ReadBuffer(PLHead,SizeOf(PLHead)); SetLength(PolyLinien,index); SetLength(PolyLinien[index-1].Parts,PLHead.NumParts); SetLength(PolyLinien[index-1].Points,PLHead.NumPoints); PolyLinien[index-1].ShapeType:=3; PolyLinien[index-1].Box:=PLHead.Box; PolyLinien[index-1].NumParts:=PLHead.NumParts; PolyLinien[index-1].NumPoints:=PLHead.NumPoints; for i:=0 to PLHead.NumParts-1 do Strom.ReadBuffer(PolyLinien[index-1].Parts[i],SizeOf(PolyLinien[index-1].Parts[i])); for j:=0 to PLHead.NumPoints-1 do Strom.ReadBuffer(PolyLinien[index-1].Points[j],SizeOf(PolyLinien[index-1].Points[j])); end; end; until (Strom.Position>=(FileHeader.FileLen*2)); // da Filesize in Word = // 16-Bit = 2 Bytes angegeben wird except error:=true; errmsg:='Fehler beim Einlesen der einzelnen Elemente bei ID : '+IntToStr(index); Strom.Free; exit; end; Strom.Free; end; procedure SwapBytes(Var Bytes; Len : Integer); // Vertauscht die Byte-Order Var swapped : PChar; // Usage : SwapBytes(i,sizeof(i)); i : Integer; begin GetMem(swapped, Len); try for i:=0 to Len-1 do swapped[Len-i-1]:=PChar(@Bytes)[i]; Move(swapped^, Bytes, Len); finally FreeMem(swapped); end; end; end. Nochmals Vielen Dank an Alle!! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:14 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz