Dateien einlesen

Hallöchen,

ich sitze nun schon seit zwei Monaten an meiner Bachelorthesis und der Großteil davon ist Programmierung (obwohl ich Maschinenbau studiere).

Jedenfalls ist es nun so, dass ich zum Weiterkommen eine Datei einlesen muss und manche Inhalte davon gerne in einen Array schreiben würde. Die Datei sieht wie folgt aus:

 LIST ALL SELECTED ELEMENTS.  (LIST NODES)
1

 ***** ANSYS - ENGINEERING ANALYSIS SYSTEM  RELEASE 15.0      *****
 ANSYS Mechanical                                 
 00200325          VERSION=WINDOWS x64   15:12:20  JAN 16, 2014 CP=      1.342

 PAL1379–Statisch-mechanisch (A5)      
                                        
    ELEM MAT TYP REL ESY SEC   NODES
 
       1       1       1     1       0     1      2   628   228    44  2791  4137  2789  2787
                                                       3076  3073
       2       1       1     1       0     1     138   300   645   351  3677  4486  3680  3678
                                                       4484  4765
       3       1       1     1       0     1     342   665   523   344  4716  5617  4713  4712
                                                       4726  4723
       4       1       1     1       0     1     342   641   523   665  4714  5615  4713  4716
                                                       6121  5617
       5       1       1     1       0     1     366   640   728   698  4828  6118  4831  4830
                                                       6117  6260
       6       1       1     1       0     1     81    497   261   571  3331  4285  3329  3332
                                                       5402  4286
       7       1       1     1       0     1     619   920   638   919  5956  6095  5952  5955
                                                       6812  6094
       8       1       1     1       0     1     29   663   641   240  2971  6120  2970  2967
                                                       4195  4194
       9       1       1     1       0     1     16  1161  1095   283  2888  7236  2887  2886
                                                       4390  4388
      10      1       1     1       0     1     24    407   135   448  2936  3661  2934  2937
                                                       5007  3662
      11      1       1     1       0     1     94   644   122   650  3420  3585  3416  3422
                                                       6127  3587
      12      1       1     1       0     1     496   613   635  2731  5392  5921  5393  5401
                                                       5924  6046
      13      1       1     1       0     1     614   781   735   765  5930  6361  5926  5928
                                                       6452  6360
      14      1       1     1       0     1     73   643   403   547  3278  4994  3272  3276
                                                       5708  4993
      15      1       1     1       0     1     78   672   334    81  3312  4677  3310  3308
                                                       3334  3330
      16      1       1     1       0     1     458   524   466   542  5233  5261  5232  5234
                                                       5621  5262
      17      1       1     1       0     1     71  2113   270   593  3264  4341  3258  3259
                                                       5864  4330
      18      1       1     1       0     1     77   520   268   612  3302  4319  3299  3303
                                                       5592  4320
      19      1       1     1       0     1     315   464   555   535  4583  5254  4585  4584
                                                       5253  5662
      20      1       1     1       0     1     516   640   698   697  5563  6117  5566  5565
                                                       6116  6258
      21      1       1     1       0     1     301  1406   636  1339  4501  6053  4490  4500
                                                       7921  6049
      22      1       1     1       0     1     88   247   150   367  3380  3738  3378  3382
                                                       4223  3741
      23      1       1     1       0     1     177   617   699   587  3888  5936  3890  3887
                                                       5837  5838
      24      1       1     1       0     1     33   417   250   696  2996  4233  2994  2998
                                                       5046  4236
      25      1       1     1       0     1     251   498   308   259  4240  4547  4239  4238
                                                       4276  4274

1

 ***** ANSYS - ENGINEERING ANALYSIS SYSTEM  RELEASE 15.0      *****
 ANSYS Mechanical                                 
 00200325          VERSION=WINDOWS x64   15:12:20  JAN 16, 2014 CP=      1.342

 PAL1379–Statisch-mechanisch (A5)                                              
 
   ELEM MAT TYP REL ESY SEC  NODES
 
      26      1       1    1      0      1     136   347  1278  2446  3668  4736  3669  3670
                                                      4739  7744
      27      1       1    1      0      1     287   522   368   501  4413  4839  4410  4412
                                                      5425  4838
      28      1       1    1      0      1     66   230   625   303  3223  4147  3225  3224
                                                      4146  4523

Und so geht diese datei dann weiter bis beispielsweise Element 2000 und nach 25 Elementen kommt dann immer dieser Zwischentext.

Das was ich brauche aus dieser Datei ist sind die erste und die letzte Spalte, wobei die letzte Spalte Knotenpunkte eines Elements sind und ich hätte gerne einen Array für die Elemente und dann hätte ich gerne, dass  jedem Element auch die ganzen Knotenpunkte zugeordnet werden , welche sich allerdings über zwei Zeilen verteilen wie man oben sieht. Ob diese Zuordnung dann auch über einen Array passieren soll ist auch eine Frage, welche ich mir stelle.

Ich weiß nun ehrlich gesagt gar nicht wie ich anfangen soll, da ich online irgendwie keinen passenden Ratgeber zum Dateien auslesen finde, da es sich dabei meist um Excel Tabellen handelt oder oftmals nur vereinzelte Zeilen rausgesucht werden sollen.

Ich arbeite übrigens mit der Software Visual Studios Express 2013.

Ich möchte jetzt hier keinen kompletten Quelltext ( worüber ich mich aber auch nciht beklagen würde :smiley: ), ich wäre schon sehr dankbar über Tipps, z.B. welche Kommandos man benutzen sollte, oder irgendwelche Links, wo mir mit meinem Problem geholfen werden kann.
Ich bin echt eine Niete im Programmieren muss ich dazu sagen und die zeit für die Abgabe meiner Thesis drückt langsam :frowning:

Ich bedanke mich schonmal im Vorraus bei Allen, die mir antworten und mich damit eventuell wieder vorran bringen.

MfG
Jens

Auch hallo

Muss man zwingend Visual Basic verwenden ?
Ansonsten könnte man die Sprache ‚Perl‘ in Verbindung mit dem Modul ‚Tie::File‘ nutzen.

mfg M.L.

Könntest du die Datei irgendwo hochladen, so dass wir uns die Datei angucken können anstatt des kopierten Inhaltes? (Bei diesem Kopieren hier rein könnten bspw. die originalen Zeilenumbruchzeichen verloren gehen etc.) Kannst ja gerne sensible Daten in der Datei entfernen oder die Datei kürzen.

Habe ich dein Problem richtig verstanden? Du willst für alle Datensätze (alle Elemente) die erste Spalte, die die Datensätze nummeriert, und die letzte Spalte extrahieren? Und von der letzten Spalte möchtest du gerne die einzelnen Zeichenketten getrennt speichern, bspw. in eine Array. So dass du für jedes Element die Nummer des Elements und ein Array hast und in dem Array die Zahlen aus der letzten Spalte gespeichert werden sollen?

So oder so würde ich vorschlagen, dass du RegEx benutzt. RegEx mutet zwar ziemlich kompliziert an, ist aber unglaublich mächtig wenn es darum geht, Strings zu manipulieren oder Bereiche aus Strings zu extrahieren.
Angenommen, dass (für alle Zeilen) nach den Daten einer Spalte mindestens ein Leerzeichen ist, kannst du so recht einfach die Tabellenstruktur der Datei wiederherstellen, und dann für alle Datensätze die erste und letzte Spalte auslesen (bzw. direkt nur die erste und letzte Spalte speichern).
Wenn du die Datei mal hochgeladen hast, kann ich dir möglicherweise eine konkretere Idee geben.

Hallo Jens,

ich sitze nun schon seit zwei Monaten an meiner Bachelorthesis
und der Großteil davon ist Programmierung (obwohl ich
Maschinenbau studiere).

warum fragste dann erst jetzt?

Jedenfalls ist es nun so, dass ich zum Weiterkommen eine Datei
einlesen muss und manche Inhalte davon gerne in einen Array
schreiben würde. Die Datei sieht wie folgt aus:

Wie auch immer da eingelesen, gefiltert, geparst werden soll so geht das höchstwahrscheinlich bei klaren Filterangaben mit mehreren Programmen.

Du hast Visual Studio, lese mal dazu die Brettbeschreibung hier im VB-Brett, du bist hier falsch.
Eine erhaltene Antwort ist ein anderes Programm zu benutzen, warum nicht, wenn es schnell erlernbar ist und der Termin für deine Thesis näherrückt.

Die angesprochene regexp-Variante ist in der Tat sehr mächtigund wer sie einigermaßen gut beherrscht kann evtl. dein Problem recht schnell lösen.
Sie sich selbst SCHNELL beizubringen, oha, äußerst heftig, *nicht empfehl*.

Gruß
Reinhard

Hallo Jens,

das macht man in VB mit dem Stream-Reader-Objekt. Hier ein Beispiel wie man zeilenweise einliest (stammt aus dem Buch „Visual Basic ohne Stress“). Ich habe das Listing etwas gekürzt. Es wird davon ausgegangen, dass Pfad und Name der einzulesenden Datei in der Stringvariablen lfilename vorliegt.

Im nachfolgenden Beispiel wird gezeigt, wie Werte aus einer Textdatei zeilenweise eingelesen werden können. Dazu wird zunächst ein StreamReader-Objekt deklariert. Bei der Instanziierung des StreamReaders wird der zu behandelnde Datenstrom (hier die Datenquelle) – im vorliegenden Fall eben eine Textdatei - angegeben.     

Option Explicit On
OptionStrict On
Public Class Form1 Private Sub ButtonRead_Click(………) Handles ButtonRead.Click  
Dim objTextFileReader As System.IO.StreamReader   'Stream zum Lesen deklarieren  
Dim lline As String  
Dim lfilename As String  
Dim lretint As Integer 'Variable zum möglichen Abbruch des Lesevorgangs   

On Error GoTo fehler1    'eine etwas primitive Fehlerbehandlung

objTextFileReader = System.IO.File.OpenText(lfilename) 'File in den Stream öffnen   

Do While (objTextFileReader.Peek() -1)      
'Peek erfaßt das nächste verfügbare Zeichen. Gibt es kein Zeichen, dann wird -1 zurückgegeben.       

lline = objTextFileReader.ReadLine 'eine Zeile einlesen       

  'MessageBox mit der Möglichkeit den Lesevorgang abzubrechen (Button OK und Cancel)      
   lretint = MessageBox.Show(lline, „Ausgabe“, MessageBoxButtons.OKCancel, _ MessageBoxIcon.None,  _
        MessageBoxDefaultButton.Button1)      

       If lretint = 2 Then          
         MessageBox.Show(„Button ‚Cancel‘ gedrückt!“)           
          Exit Do      
        End If  
   Loop 

   fehler1:   'falls beim Zugriff ein Fehler auftaucht wird der Reader wieder geschlossen   objTextFileReader.Close()   

   End Sub
End Class

Viele Grüße
Franz Peter

Hallo Jens,
da ich C# programmiere und mir die Syntax von VB nicht so geläufig ist, habe ich versucht, einen groben Lösungsansatz mit einer Mischung aus VB und Pseudocode darzustellen.
ich würde es so machen:

Klasse „ElementInfo“ definieren mit folgenden Properties:
    Int Element
    List Knotenpunkte
                
Dann in Deiner Hauptklasse:
Dim elementInfos As List
Dim dateitext As DateiEinlesen(Dateiname)
Dim regex As new Regex("^\d*\s*[0-1]\s*[0-1]\s*[0-1]\s*[0-1]\s*[0-1]\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*$")
Dim matches As MatchCollection = regex.MatchCollection(dateitext)

For Each match As Match in matches
    Dim elementInfo As ElementInfo
    elementInfo.Add(Erste Zahl) (Dazu musst Du den Substring bis zum ersten Leerzeichen extrahieren)
    Letzte Zahlenkette (Knotenpunkte) durchlaufen und zu elementInfo.Knotenpunkte hinzufügen (dazu kannst Du das selbe Prinzip mit Regex und dem Durchlaufen der Matches hier nochmal anwenden)
Next

Danach kannst Du die Liste elementInfos enfach durchlaufen und zu jeder enthaltenen elementInfo wiederum die darin enthaltene Liste der Knotenpunkte durchlaufen. Also 2 ineinander verschachtelte Schleifen.

Das Regex habe ich nicht getestet, müsste aber ungefähr hinkommen. Das ^ repräsentiert den Zeilenanfang, das $ ein Zeilenende. [0-1] repräsentiert eine Ziffer zwischen 0 und 1. Das \d steht für eine Ziffer. Das \s steht für ein Leerzeichen. Falls Tabs dazwischen sind, musst Du es entsprechend anpassen (wahrscheinlich \t, bin mir aber nicht ganz sicher)

Ich hoffe, das hilft Dir. Viel Erfolg,
Michael

Hallo Franz,

erstmal herzlichen Dank für ausführliche Antwort!

Aber wo in diesem Quelltext werden die Arrays für die erste und letzte Spalte aufgestellt?

MfG
Jens Wala

Hier ist der Download Link:

http://www.file-upload.net/download-8535830/elist-ds…

Vielleicht hast du ja damit noch eine andere Idee. Trotzdem schonmal Danke für die Antwort

Ok, das müsste recht einfach möglich sein, die Daten, die du haben willst, zu extrahieren. Habe mal ein RegEx-Pattern gebastelt, das auch sicher funktioniert.
Michael T.s Antwort scheint ein recht professioneller Weg zu sein, dem du vielleicht Vorrang geben solltest. Meiner funtkioniert aber ebenfalls, wenn auch vielleicht nicht so elegant (zumal meine RegEx-Kenntnisse soweit reichen, ein Pattern basteln zu können, aber das aber elegant oder besonders ressourcenschonend ist kann ich nicht sagen.

Das RegEx-Pattern ist letztlich das Herzstück der Angelegenheit. Es sorgt dafür, dass du aus dem gesamten Text der Datei für jeden Datensatz einen String bekommst, der die gesuchten Elemente enthält. Diesen String musst du dann nur noch für jeden Datensatz aufdröseln in die einzelnen Elemente und sie in ein Array packen.

Das RegEx-Pattern lautet wie folgt:
^[]+\d+(?:[]{3}\d){5}((?:[]+\d+)+(?:\n[]{8,}(?:[]+\d+)+)*)
Sieht für das ungeübte Auge verdammt kompliziert aus, aber wenn man sowas entwickelt geht das Schritt für Schritt und ist letztlich garnicht mehr so unübersichtlich.
Ich möchte dir das gern erklären, auch wenn du es einfach so übernehmen könntest.

RegEx funktioniert so, dass der RegEx-Interpreter aus dem Originaltext alle Übereinstimmungen mit dem RegEx-Pattern zurückgibt. Das RegEx-Pattern kann nur ein Textstück sein, das du in dem Text suchen willst, was jedoch nur geringen Verwendungszweck hätte. Deswegen gibt es Sonderzeichen im RegEx-Pattern, die vom Interpreter besonders behandelt werden, womit man die zu findenden Übereinstimmungen mehr einschränken und das Suchmuster allgemeiner formulieren kann.
^ repräsentiert einen Zeilenanfang. Mit diesem RegEx-Pattern werden also nur Teile gefunden, die - natürlich - dem Rest hinter dem ^ entsprechen, aber eben nur solche, die direkt am Zeilenanfang stehen.
[] stellt - vereinfacht gesagt - ein Leerzeichen dar.
Ein + hinter einem Symbol oder einem geklammerten Ausdruck bedeutet, dass das Vorhergehende einmal oder öfter vorkommen muss. Der RegEx-Interpreter kann also []+ einer beliebigen Folge von Leerzeichen zuordnen (solange es mindestens ein Leerzeichen ist).
\d findet eine Ziffer. Entsprechend findet \d+ eine oder mehrerr Ziffern hintereinander.
( und ) Klammern den enthaltenen Ausdruck, so dass bspw. ein +, das hinter der Klammer steht, auf den gesamten Ausdruck in der Klammer angewendet wird. Normalerweise bedeutet das auch gleichzeitig, dass das Textstück, das dem Ausdruck in der Klammer entspricht, als Gruppe „gespeichert“ wird (auf die mal anschließend im Code des Programmes gesondert zugreifen kann). Wenn am Anfang in der Klammer jedoch ein ?: steht, bedeutet das, dass diese Klammer den Inhalt nicht gruppiert. Das ist hilfreich, da zu viel Gruppieren die Performance senkt.
{x} gibt an, dass der voranstehende Ausdruck genau x mal vorkommen muss (genauso wie ein + bedeutet, dass der Ausdruck einmal oder mehrmals vorkommen muss). {x,} bedeutet, dass er mindestens x mal vorkommen muss, aber auch öfter vorkommen kann.
\n entspricht einem Zeilenumbbruch.
* ist wieder ähnlich dem +, jedoch kann der Ausdruck auch keinmal vorkommen.

Ich erklär nochmal die einzelnen Abschnitte des Patterns: (es ist hilfreich, sich eine Zeile aus dem Originaltext dazu anzugucken:smile:
1 1 1 1 0 1 2 628 228 44 2791 4137 2789 2787
3076 3073

^[]+\d+
Findet eine beliebige Anzahl an Leerzeichen mit einer nachfolgenden beliebigen Anzahl an Ziffern; das ganze muss am Zeilenanfang stehen (die Leerzeichen am Anfang jeder Zeile, sowie die Nummer, die alle Datensätze fortlaufend nummeriert)

(?:[]{3}\d){5}
Findet ein Muster aus drei nacheinander stehenden Leerzeichen und einer anschließenden Ziffer, und zwar nur, wenn das Konstrukt fünf mal hintereinander vorkommt (die Werte der fünf Spalten zwischen der Zeile mit der Nummer und den eigentlichen Daten).

(
Beginnt die einzige Gruppe, die wir auch wirklich „speichern“ (alle anderen haben ein ?: am Anfang). Sie wird die eigentlichen Daten enthalten.

(?:[]+\d+)+
Eine beliebige Anzahl Leerzeichen mit folgender beliebiger Anzahl Ziffern, was wiederum mehrmals vorkommen kann (der Teil mit den Daten, zumindest in der aktuellen Zeile).

(?:\n[]{8,}
Ein Zeilenumbruch, gefolgt von mindestens acht Leerzeichen (nötig, um Zeilen, in denen Daten stehen, die aber kein neuer Datensatz sind, zu identifizieren (also dort, wo die Daten in einer neuen Zeile stehen), da diese mit mindestens acht Leerzeichen beginnen, andere Zeilen aber nie so viele Leerzeichen am Anfang haben).

(?:[]+\d+)+
Wie oben wieder (findet die Daten, die in dieser neuen Zeile stehen).

)
Schließt die davor geöffnete Gruppe, womit die Gruppe für den momentanen Datensatz alle eigentlichen Daten enthält (ob diese nur in der ersten Zeile stehen, oder über mehrere verteilt sind, ist dabei egal).

*)
Der Stern * sorgt dafür, dass das Konstrukt, welches die neue Zeile mit den eingerückten Daten repräsentiert, optional ist oder mehrmals vorkommen kann. Somit werden Datensätze gefunden, die alle Daten in nur einer Zeile haben, in einer weiteren Zeile oder in noch mehr Zeilen.

(Sorry dass alles so ausführlich ist :stuck_out_tongue:)

Im Internet gibt es einen Haufen von RegEx-Testern. Wenn du da das ganze mal eingibst, wirst du sehen, wie es funktioniert.

In Visual Basic kannst du nun in deinem Programm mit diesem RegEx-Pattern die Daten herausziehen.
Als erstes musst du die Datei einlesen und in einem einfachen String speichern (Zeilenumbrüche sind nichts anderes als besondere, nicht sichtbare Zeichen, daher kann man eine Datei in einem String speichern).
Die RegEx-Engine rufst du auf über die Klasse Regex in System.Text.RegularExpressions (das zu importieren wäre hilfreich, mit Imports System.Text.RegularExpressions ganz am Anfang der Codedatei). Diese stellt eine statische Methode Matches zur Verfügung, welche du direkt verwenden kannst. Wichtig: Neben dem Pattern (als ganz normalen String) und dem Text der Datei, die du der Methode übergeben musst, musst du auch die Multiline-Option übergeben (RegexOptions.Multiline, du siehst was gemeint ist, wenn du es dir in Visual Studio anguckst).
Die von der Methode zurückgegebene MatchCollection kannst du am einfachsten mit einer For-Each-Schleife durchlaufen. Die erste Group eines einzelnen Elements dieser MatchCollection und davon das Attribt Value enthält den Datenstring (also .Groups(1).Value). Dieses entählt die einzelnen Zahlen, aber mit den Leerzeichen noch dazwischen. Da musst du dir jetzt die einzelnen Zahlen rausfischen (das könnte man auch mit nem zweiten RegEx machen… „\d+“ würde da als Pattern reichen, um die Zahlen zu finden). Diese speicherst du in ein Array (oder eine ArrayList, das ist evtl. einfacher) und diese Arrays oder ArrayLists kannst du in einer großen List speichern (List initialisiert eine List mit Datenelementen vom Typ String-Array).

Das wäre letztlich alles… Google einfach mal, wie man die einzelnen Sachen macht. wenn du beim Googeln „msdn“ mit angibst, findest du oft eine MSDN-Unterseite, welche eine Art offizielle DOkumentation enthält und sehr hilfreich sein kann. Ansonsten, guck auch mal in die IntelliSense-Vorschläge, wenn du was in den Codeeditor tippst (diese Box, die sich aufklappt), da sind oft gute Beschreibungen dabei.

Wenn du selber nicht weiterkommst, kann ich dir falls nötig auch noch etwas mehr helfen. Wann ist denn die Abgabe? :wink:

Auf alle Fälle herzlichen Dank. Das hat mir wirklich sehr weiter geholfen.
Danke dass du dir so viel Zeit für eine solch ausführliche Antwort gegeben hast.

Eigentlich müsste der Rest jetzt von alleine laufen aber falls es irgendwo stockt komme ich gerne auf dein Angebot zurück :smile:

Abgabe ist Anfang März.

Freut mich, dass ich helfen konnte :smile:

Dann noch viel Glück bei der Bachelor-Arbeit!