Hi Leute Würde es gerne ordentlich machen, finde aber kein Beispiel dafür. Also, ich habe eine Binärdatei aus welcher ich an bestimmten Stellen bestimmte Bytes benötige und in bestimmten Variablen abspeichern muß. Wie man die Datei einliest weis ich, ich habe aber Probleme mit der Organisation der benötigten "Angaben" bzw. deren Umsetzung. Also: - Ich weis die Byte-Startposition - Ich weis die Byte-Länge - Ich weis den Variablennamen unter dem das/die ausgelesene/n Byte(s) gepeichert werden soll/en. Wie realisiert man das nun "intelligent" ? Über Serialisierung ist schwer, da zwischendrin "Lücken sind", außerdem will ich nicht erst die ganze Datei einlesen, sondern eben immer nur die Stellen, die ich benötige damits schneller geht. Mein Problem ist eine Lösung zu finden, bei der man eben die Angaben zu "Variable", "Position" und "Länge" schön verbindet und darüber dann "in einem Rutsch" die Datei auslesen kann. Als Array mit Schleife würds sicher gehen, ich frag mich aber obs da noch bessere Wege oder Möglichkeiten gibt ... MFG Marco
Hallo Marco, es gibt das sowas, wird MSDN genannt. Mit sämtlichen Infos, die Du benötigst... ;-) Hast Du schonmal in Erwägung gezogen System.IO.BinayReader.Read(byte[] buffer,int index,int count) zu bemühen? Gruß Markus
Ja, MSDN kenne ich ... grauenhaft unübersichtlich :-) Aber das ist ja nicht mein Problem, denn: > Wie man die Datei einliest weis ich, ich habe aber Probleme mit der > Organisation der benötigten "Angaben" bzw. deren Umsetzung. Mich interessiert die Organisation der Daten die dahinter steht, nicht das auslesen der Daten ansich, das kann ich schon einigermaßen. Ich habe mehrere Variablen im Programm die ich mit Daten aus der einzulesenden Datei füttern möchte. Position und Länge innerhalb der Datei weiß ich für jede Variable einzeln. Mein "Problem" ist einen schönen Weg zu finden das "übersichtlich" zu organisieren, denn ich muß jedesmal den Seek neu setzen und eine unterschledliche Länge an Bytes einlesen und speichern. Zuerst dachte ich daran, lauter Structs zu definieren und in jedem 3 Einträge zu machen: - VALUE = speichert eingelesenen Wert - readonly POSITION = Position innerhalb der Datei - readonly LENGTH = Länge der Information innerhalb der Datei Diese Structs (für jede Variable eine eigene) wollte ich dann in ein weiteres Struct packen und dann per "foreach" jedes Struct auslesen lassen und daraus dann auf die Datei zugreifen. Dabei greife ich dann über die 3 verschiedenen Einträge auf alle Informationen zu. Leider geht das nicht ganz so einfach weil mit Structs keine "foreach-Schleife" möglich ist, dann wirds da schon wieder (für Anfänger) umständlich. So hätte ich alle Informationen zu einer einzigen Variable zentral an einem Ort (Name, ausgelesener Wert, und Position in der auszulesenden Datei). Zugriff auf den eigentlichen Wert wäre dann auch sehr komfortabel über HAUPTSTUCT.VARIABLE.VALUE möglich, so hätte ich das "irgendwie" gerne. Vielleicht wird jetzt deutlicher was ich meine. Eventl. gibts ja auch eine andere bessere Methode ...
Hi Marco, haben die Daten, die Du aus der Datei auslesen willst, immer den selben Typ, oder ist das mal ein int, dann ein Byte-Array usw...? Dann stellt sich für einen Lösungsvorschlag noch die Frage, wie willst Du die Daten nach dem Lesen weiterverarbeiten? Das was Du vor hast, ist aber prinzipiell schon möglich, wobei es immer mehr oder weniger große "Aber" gibt. Bevor ich Dir den Lösungsweg zeigen kann, sollte ich aber die obigen Infos haben. Markus
>ich nicht erst die ganze Datei einlesen, sondern eben immer nur die >Stellen, die ich benötige damits schneller geht. Das wird vermutlich nichts werden, ausser C# kennt sowas wie "seek" (aus Pascal), mit dem man an bestimmte Stellen in der (Text-)Datei springen kann. Ich gehe davon aus, dass du die Anzahl der zu lesenden Bytes und deren Position in der Datei kennst, und diese konstant ist. Dann ist es am einfachsten, ein Array mit den Adressen und vielleicht auch noch der Anzahl hintereinander zu lesender Bytes) zu machen und die Datei dann einfach von vorne nach hinten einzulesen (vielleicht auch blockweise, was die Sache etwas verkompliziert), und die aktuelle Leseposition mit der nächsten aus der Adresstabelle vergleicht. Dann kopiert man die Bytes halt in eine Variable (wenn die Variablen feste Namen haben, braucht man noch ein switch-Case-Abfrage, die über den Adress-Array-Index arbeitet.
Schon einmal Danke für Eure Antworten. Hab weiter über googlen versucht mal einen möglichen Weg zu finden, bin aber leider gescheitert. Also, die Daten sind Binär, mal ist das Datum ein byte lang, mal zwei, drei oder vier Bytes. Typ ist immer derselbe, in der Binärdatei (keine Textdatei) halt Byte (HEX) und auslesen und "speichern" tue ich dann natürlich als 32bit-Integrer. Speichern wollte ich sie ursprünglich gerne in einem struct, damit ich jedem Abschnitt einen struct zuordnen kann und die darin enthaltenen Infos dann als int zusammenfassen kann. Somit hat man (gerade als Anfänger wichtig) eine schöne Übersicht und hat die Daten "gesammelt" an einer Stelle (in dem Struct). "SEEK" gibt es in C#, um beim Auslesen mehr Geschwindigkeit zu erhalten möchte ich deshalb die Stellen jedesmal gezielt anspringen um unnötiges auslesen von nicht benötigten Daten zu verhindern. Anzahl der Bytes und deren Position kenne ich wie gesagt. Dieses Muster wiederholt sich mehrmals in der gesamten Datei bei prinzipiell gleichem Abstand (2048 bytes). Es gibt also jedesmal einen Grundoffset und dann den individuellen Offset für jedes Datum. Das ist ja aber über ne einfache Schleife kein Problem. @ STK500-Besitzer: Prinzipiell hab ichs verstanden, aber auch das benötigt eine Menge Code und viele SWITCH-Abfragen, brauchte dann: 1 Positionsarray 1 Längenarray 1 Speicherarray also alles verstreut und sehr fehleranfällig wie ich finde. Bei meinem "Struct" wäre es ja dann quasi so: STRUCTNAME DATUM |-> DATUMSWERT int32 |-> POSITION int64 |-> LÄNGE byte Alles ordentlich sortiert und direkt sichtbar zuordbar. Gefällt mir als Anfänger sehr gut, weil sehr übersichtlich und kaum fehleranfällig. Was ich meine mal gesehen habe ist eine Art Multiarray, finde aber nichts dazu. Also quasi ein Multidimensionales Array, aber mit unterschiedlichen Typen. Diese würde ich dann in eine Arraylist setzen und gut wäre ... Soweit ich weis kann man aber ein Multiarray nicht mit verschiedenen Typen kombinieren. Beispiel wäre dann z.B.
1 | int[,] numbers = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} }; |
Das wäre es ja schon fast, bläht aber den Speicher unnötig auf (wegen dem int64 (Position)). Zudem gibts keine Benennung der Variable in der der Wert dann gespeichert werden soll. Ließe sich zwar auch mit ner Schleife lösen, aber das finde ich sehr unschön und mehr als unprofessionell. Hinkriegen würd ichs irgendwie, mir fehlt aber der Feinschliff, das geht bestimmt noch besser ... :-) Es ist garnicht so leicht eine Variable zu erzeugen und dann eine entsprechende Position mit bekannter Länge aus einer Datei auszulesen.
Ich sehe das Problem im Moment darin, das Du nicht klar erklären kannst was eigentlich Dein Ziel ist. Einerseits magst Lösungen die: intelligent, schön, übersichtlich sind, aber das sind keine objektivierbaren Kriterien. und Deine Kritik an den möglichen Lösungen ist damit völlig undifferenziert. Wenn Du meinst: >STRUCTNAME DATUM >|-> DATUMSWERT int32 >|-> POSITION int64 >|-> LÄNGE byte ist eine sinnvolle Lösung, denn mach das doch so. Ich meine, das Du noch nicht über genug Erfahrung verfügst, um verschiedene Lösungen zutreffend zu charakterisieren. Diese Erfahrung musst Du (wie jeder Andere auch) erwerben in dem Du erstmal verschiedenes probierst und vergleichst. Dann würdest Du auch Deine Frage selbst beantworten können.
Hi Marco, mir ist zwar immer noch nicht ganz klar, wie Du die Daten weiter verarbeiten willst, aber ich habe Dir mal eine kleine Klasse (anstelle eines struct) als Beispiel. In C# gibt es nur geringfügige Unterschiede zwischen struct und class, die für Dein Vorhaben eher nicht relevant sein sollten. Wenn es Dich interessiert, wo der Unterschied liegt, dann google mal danach... Hier jetzt das versprochene Beispiel:
1 | public class DataReader |
2 | {
|
3 | public DataReader(BinaryReader reader, long position, int size) |
4 | {
|
5 | if (reader == null) |
6 | throw new ArgumentNullException("reader"); |
7 | if (size < 1 || size > 4) |
8 | throw new ArgumentOutOfRangeException("size", size, "Wert muß im Bereich von 1..4 sein."); |
9 | _position = position; |
10 | _size = size; |
11 | _fileData = 0; |
12 | reader.BaseStream.Position = _position; |
13 | for (int count = 0; count < _size; count++) |
14 | {
|
15 | _fileData += (int)(reader.ReadByte() << (count * 8)); // little endian |
16 | //_fileData = ((int)(_fileData << 8)) + reader.ReadByte(); // big endian
|
17 | }
|
18 | }
|
19 | |
20 | private long _position; |
21 | public long Position { get { return _position; } } // read only property |
22 | |
23 | private int _size; |
24 | public int Size { get { return _size; } } // read only property |
25 | |
26 | private int _fileData; |
27 | public int FileData { get { return _fileData; } } // read only property |
28 | }
|
29 | |
30 | class Program |
31 | {
|
32 | static void Main(string[] args) |
33 | {
|
34 | BinaryReader reader = new BinaryReader(new FileStream("filepath", FileMode.Open)); |
35 | List<DataReader> list = new List<DataReader>(); |
36 | try { new DataReader(null, 1, 1); } |
37 | catch { Console.WriteLine("Exception hier erwartet."); } |
38 | try { new DataReader(reader, 1, 0); } |
39 | catch { Console.WriteLine("Exception hier erwartet."); } |
40 | list.Add(new DataReader(reader, 4, 1)); |
41 | list.Add(new DataReader(reader, 5, 2)); |
42 | list.Add(new DataReader(reader, 7, 3)); |
43 | list.Add(new DataReader(reader, 10, 4)); |
44 | foreach (DataReader value in list) |
45 | {
|
46 | int data = value.FileData; |
47 | Console.WriteLine( |
48 | string.Format("data[{0},{1}]: {2}", value.Position, value.Size, data) |
49 | );
|
50 | }
|
51 | }
|
52 | }
|
Die Klasse DataReader speichert Position und Größe und ermittelt im Konstruktor den gewünschten Wert aus Deiner Datei. Du mußt noch herausfinden, wie Deine Daten in der Datei vorliegen (Little oder Big Endian) und die entsprechende Zeile im Konstruktor aktivieren und die andere Zeile löschen. Die Berechnung des int-Wertes habe ich nicht so ausführlich getestet, das überlasse ich dann Dir... ;-) Viel Spaß Markus
@Markus: Anscheinend ist Dir aber doch klar was ich möchte :-))))) !! DANKE !! Dein Beispiel ist absolut TOP ! Tut mir leid, aber ich habe Deine Frage bzgl. der Verwendung der Daten nicht verstanden. Im Grunde genommen möchte ich nachher nur die einzelnen _fileData abfragen, also der Binärwert (in int) der an der entsprechenden Position im File stand. Das dann natürlich in einer Schleife. Mit Deinem Beispiel geht das ja genau so, wie ich mir das vorstelle. Auch der Rest vom Code ist mehr als hilfreich für mich, er zeigt eine saubere Programmierung und mir werden dadurch jetzt viele Dinge klar, die ich vorher mal gelesen, aber aufgrund eines fehlenden Zusammenhanges nicht verstanden hatte. An Deinem praktischen Beispiel hier wirds mir sofort klar und ich kann es jetzt auch direkt einbinden. @Ahem: Muß Dir vollkommen Recht geben, das ist halt die Erfahrung die fehlt. Bei Kleinigkeiten probier ist selber aus, aber das hier ist ein größerer Teil meines Programmes und da möchte ich sehr schlechten Code vermeiden und es schon möglichst optimal haben. Dafür sollte ein Forum da sein, auch wenn es wohl ne ziemlich blöde Frage eines Anfängers ist, die zudem wohl auch ziemlich undeutlich gestellt wurde. MFG Marco
Hi Marco, meine Frage bezüglich des "Verwendungszwecks" habe ich deshalb gestellt, weil Du in dem Beispiel eigentlich nichts anderes als eine Liste oder eine Art Array mit int-Werten bekommst, in der wenig Informationen über die Quelle, oder genauer, den Typ der Quelle zur Verfügung steht. Man kann bei entsprechender Kenntnis wahrscheinlich noch mehr Logik in die Klasse(n) packen, was Programme wesentlich robuster macht. So sauber, wie Du annimmst, ist mein Code übrigens nicht. Es fehlt zum Beispiel die Exception-Behandlung für die IO-Methoden. Außerdem habe ich mir wenig Gedanken gemacht, ob die Berechung des int-Wertes korrekt ist, ... Das ist übrigens nicht der Fall: byte ist unsigned, int ist signed. Also entweder mußt Du int und reader.ReadSByte() oder uint und reader.ReadByte() verwenden. Ich falle immer wieder darauf rein: int und uint, byte und sbyte, ist doch logisch, oder? ;-) Dein Startposting zeigt übrigens, daß Du Dich schon mit Deinem Problem beschäftigt hast, aber über eine bestimmte Hürde nicht drüber kommst. Kein schreibt-mir-doch-mal-jemand-meine-Hausaufgaben. Es ist keine Schande, mal irgendwo nicht weiter zu kommen, als Anfänger sowieso nicht. Wie Du richtigt angemerkt hast, für sowas ist das Forum da. Gruß Markus
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.