Blöcke aus Datei filtern/suchen und in neue Datei schreiben

ralfb1105

Bekanntes Mitglied
Hallo zusammen,

ich benötige mal wieder einen Denkanstoß für folgendes Problem.
Ich habe eine Datei die im Prinzip folgenden Aufbau hat:
Code:
360030057022ae9401e29346c3ba7c3c5 dm-0 FTS,PRAID EP420i
size=120G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=1 status=active
  `- 0:2:1:0   sdb  8:16   active ready running
3600000e00d2b0000002b01b001450000 dm-1 FUJITSU,ETERNUS_DXH
size=15G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:10  sdu  65:64  active ready running
  |- 1:0:0:10  sdc  8:32   active ready running
  |- 4:0:1:10  sdad 65:208 active ready running
  `- 1:0:1:10  sdl  8:176  active ready running
3600000e00d2b0000002b01b001910000 dm-3 FUJITSU,ETERNUS_DXH
size=70G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:40  sdw  65:96  active ready running
  |- 1:0:0:40  sde  8:64   active ready running
  |- 4:0:1:40  sdaf 65:240 active ready running
  `- 1:0:1:40  sdn  8:208  active ready running
3600000e00d2b0000002b01b0015c0000 dm-4 FUJITSU,ETERNUS_DXH
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:200 sdx  65:112 active ready running
  |- 1:0:0:200 sdf  8:80   active ready running
  |- 4:0:1:200 sdag 66:0   active ready running
  `- 1:0:1:200 sdo  8:224  active ready running

Ein Device Block besteht immer aus folgenden Zeilen:
1. Zeile: WWPN deviceName Vendor
2. Zeile: Size Features
3. Zeile: Policy Status
4+n Zeilen: Phys. Devices, wobei die Anzahl variieren kann.

Hinweis:

Es kann auch vorkommen das die Anzahl der Zeilen für die phys. Devices unterschiedlich ist, also z.B. folgender Output:
Code:
360030057022ae9401e29346c3ba7c3c5 dm-0 FTS,PRAID EP420i
size=120G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=1 status=active
  `- 0:2:1:0   sdb  8:16   active ready running
3600000e00d2b0000002b01b001450000 dm-1 FUJITSU,ETERNUS_DXH
size=15G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  `- 1:0:1:10  sdl  8:176  active ready running
3600000e00d2b0000002b01b001910000 dm-3 FUJITSU,ETERNUS_DXH
size=70G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:40  sdw  65:96  active ready running
  |- 1:0:0:40  sde  8:64   active ready running
  |- 4:0:1:40  sdaf 65:240 active ready running
  `- 1:0:1:40  sdn  8:208  active ready running
3600000e00d2b0000002b01b0015c0000 dm-4 FUJITSU,ETERNUS_DXH
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:200 sdx  65:112 active ready running
  |- 4:0:1:200 sdag 66:0   active ready running
  `- 1:0:1:200 sdo  8:224  active ready running

Weiterhin kann es auch zwei Zeilen mit Policy geben:
Code:
3600000e00d2a0000002a0c9905de0000 dm-2 FUJITSU,ETERNUS_DXM
size=1.5T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='round-robin 0' prio=50 status=active
| |- 11:0:1:2 sdg 8:96  active ready running
| `- 12:0:1:2 sdm 8:192 active ready running
`-+- policy='round-robin 0' prio=10 status=enabled
  |- 11:0:0:2 sdd 8:48  active ready running
  `- 12:0:0:2 sdj 8:144 active ready running

Aufgabe:

Ich benötige die "Blöcke", sprich die Zeilen 1-4+n eines bestimmten Vendors in einer Result Datei.

Diese Datei sollte dann bezogen auf das oben gezeigte Beispiel folgenden Inhalt haben:
Code:
3600000e00d2b0000002b01b001450000 dm-1 FUJITSU,ETERNUS_DXH
size=15G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:10  sdu  65:64  active ready running
  |- 1:0:0:10  sdc  8:32   active ready running
  |- 4:0:1:10  sdad 65:208 active ready running
  `- 1:0:1:10  sdl  8:176  active ready running
3600000e00d2b0000002b01b001910000 dm-3 FUJITSU,ETERNUS_DXH
size=70G features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:40  sdw  65:96  active ready running
  |- 1:0:0:40  sde  8:64   active ready running
  |- 4:0:1:40  sdaf 65:240 active ready running
  `- 1:0:1:40  sdn  8:208  active ready running
3600000e00d2b0000002b01b0015c0000 dm-4 FUJITSU,ETERNUS_DXH
size=2.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=50 status=active
  |- 4:0:0:200 sdx  65:112 active ready running
  |- 1:0:0:200 sdf  8:80   active ready running
  |- 4:0:1:200 sdag 66:0   active ready running
  `- 1:0:1:200 sdo  8:224  active ready running

Was ich schon habe ist die Zeile 1, sprich die mit dem Vendor (z.B. FUJITSU,ETERNUS_DXH), heraus zu suchen und in eine Datei "Results.txt" zu schreiben. Hier mal der hierfür relevante Code:

Java:
public static void main(String args[]) throws IOException {

        File sourceFile = new File("C:\\Users\\PDBRBOER\\Downloads\\multipath-ll.txt");
        FileReader fr = new FileReader(sourceFile);
        BufferedReader bufr = new BufferedReader(fr);
        final String resultFile = "C:\\Users\\PDBRBOER\\Downloads\\Results.txt";
        FileWriter fw = null;
        BufferedWriter bw = null;
        PrintWriter out = null;

        try {
            fw = new FileWriter(resultFile, true);
            bw = new BufferedWriter(fw);
            out = new PrintWriter(bw);
        } catch (Exception e) {
            e.printStackTrace();
        }

        int count = 0;
        int countFJEternusDevices = 0;

        String line = bufr.readLine();

        while (line != null) {
            String[] splitLineArray = line.split(" ");
            if (splitLineArray[2].equals("FUJITSU,ETERNUS_DXH")) {
                countFJEternusDevices++;
                out.println(line);
            }
            count++;
            line = bufr.readLine();
        }
        System.out.println("Number of lines: " + count);
        System.out.println("Number FUJITSU,ETERNUS_DXH devices: " + countFJEternusDevices);

        try {
            if (out != null)
                out.close();
            if (bw != null)
                bw.close();
            if (fw != null)
                fw.close();
            if (bufr != null)
                bufr.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Wo ich jetzt hänge, ich weiß nicht wie ich die nächsten zugehörigen Zeilen, die auf das ermittelte Device folgen, bestimmen und dann in die Datei schreiben soll?

Hat jemand hier eine Idee?

Gruß

Ralf
 
Zuletzt bearbeitet:
Meinst Du so in der Richtung?
Java:
import java.io.*;
import java.util.*;

public class Test {
    public static void main(String[] args) throws IOException {
        PrintStream out = System.out; 
        try(BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
            List<String> block = new ArrayList<>();
            String line;
            while ((line = reader.readLine()) != null) {
                if (Character.isDigit(line.charAt(0))) {
                    process(out, block);
                    block = new ArrayList<>();
                }
                block.add(line);
            }
            process(out, block);
        }
    }

    private static void process(PrintStream out, List<String> block) {
        if (block.isEmpty()) {
            return;
        }
        String subject = block.get(0).split(" ")[2];
        if (!"FUJITSU,ETERNUS_DXH".equals(subject)) {
            return;
        }

        for (String line : block) {
            out.println(line);
        }
    }
}
 
Hallo mihe7,

😵 mal ehrlich .. nur unter uns 😎 hast Du das jetzt in den 2 Minuten geschrieben oder hattest Du schon mal so eine Fragestellung?
Ich habe es gerade getestet, und wie nicht anders von Dir zu erwarten macht es genau das was es soll - Chapeau!!

Ich muss es mir jetzt noch im Detail anschauen um es zu verstehen, ich wäre da aber vermutlich in 10 Jahren nicht drauf gekommen. Wie Du siehst, ich bin echt begeistert!!!

Gruß

Ralf
 
hast Du das jetzt in den 2 Minuten geschrieben oder hattest Du schon mal so eine Fragestellung?
Ich schreibe hier so gut wie immer alles neu. Das Prinzip ist aber nichts ungewöhnliches: Beginn erkennen und bis zum nächsten Beginn puffern.

Wobei ich gerade sehe, dass man es besser machen hätte können, da man das Blockende erkennen kann, so dass das nochmalige process am Ende entfallen könnte.

EDIT: Hier noch die überarbeitete main-Methode:
Java:
    public static void main(String[] args) throws IOException {
        PrintStream out = System.out; 
        try(BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
            List<String> block = new ArrayList<>();
            String line;
            while ((line = reader.readLine()) != null) {
                block.add(line);
                if (line.startsWith("  `")) {
                    process(out, block);
                    block = new ArrayList<>();
                }
            }
        }
    }
 
Ich schreibe hier so gut wie immer alles neu. Das Prinzip ist aber nichts ungewöhnliches: Beginn erkennen und bis zum nächsten Beginn puffern.

OK, die Begeisterung steigt weiter!
Ich habe mir den Code jetzt angesehen und auch soweit verstanden.
Nachdem ich es jetzt gesehen habe, wobei es dann natürlich immer einfach ist es zu sagen 😉 fehlte mir Hauptsächlich das umsetzen in ein Array. Hier muss ich mehr an mir arbeiten - da fehlen mir noch etliche Programmierer Gehirnzellen 😱

VIELEN Dank für die schnelle Hilfe.

Gruß

Ralf
 
Wobei die ersten Ideen nicht immer die besten sind:

Java:
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.io.PrintStream;
import java.util.function.Predicate;

public class Test {
    static class BlockFilter implements Predicate<String> {
        private boolean writing;
        private final Predicate<String> subjectFilter;

        public BlockFilter(Predicate<String> filter) {
            subjectFilter = filter;
        }

        @Override
        public boolean test(String line) {
            if (Character.isDigit(line.charAt(0))) {
                String subject = line.split(" ")[2];                
                writing = subjectFilter.test(subject);
            }
            return writing;
        }
    }

    public static void main(String[] args) throws IOException {
        PrintStream out = System.out;
        BlockFilter block = new BlockFilter(s -> s.equals("FUJITSU,ETERNUS_DXH"));
        Files.lines(Paths.get("test.txt"))
            .filter(block)
            .forEach(out::println);
    }
}
 
Jetzt willst Du es aber wissen 🙂 nach dem überfliegen muss ich gestehen das ich es noch nicht zu 100% verstanden habe wie der Code funktioniert 😵 werde ich mir Morgen noch einmal genauer ansehen. Da waren Sie wieder ... meine Defizite mit Lambda & Co. 😉

Was mir auf Anhieb überhaupt nichts sagt ist der Code:
Java:
Files.lines(Paths.get("test.txt"))
            .filter(block)
            .forEach(out::println);
Aus dem Bauch würde ich das so interpretieren:
Das File test.txt wird Zeile für Zeile gelesen und durch den BlockFilter geschickt, wobei der Block anfängt wenn das erste Zeichen eine Zahl ist. Alle die durch den Filter kommen werden dann durch die forEach mit Hilfe von out und println ausgegeben. Wobei mir hier die Syntax (out:😛rintln) nichts sagt.

Gruß

Ralf
 
Das File test.txt wird Zeile für Zeile gelesen und durch den BlockFilter geschickt, wobei der Block anfängt wenn das erste Zeichen eine Zahl ist. Alle die durch den Filter kommen werden dann durch die forEach mit Hilfe von out und println ausgegeben
Das trifft es ziemlich gut. Die Ausführung ist aber lazy: Files.lines() liefert einen Stream (java.util.stream.Stream) der Zeilen der Datei zurück. Mittels filter() wird daraus ein gefilterter Stream "gemacht" und erst forEach sorgt dann für die Abarbeitung des Ganzen. D. h. würde man nur Files.lines(Paths.get("test.txt")).filter(block) schreiben, würde aus der Datei keine Zeile gelesen.

Das out::println ist eine Methodenreferenz. Mit einem Lambda-Ausdruck hätte das so ausgesehen: forEach(line -> out.println(line)).
 
Danke für die Erklärung. Jetzt habe ich aber gleich noch eine Frage zu dem BlockFilter. Ich verstehe im Moment noch nicht ganz wie Du den ganzen Block erkennst. Ich verstehe das Du die line auf den ersten Character nach einer Zahl „absuchst“ und wenn es eine Zahl ist wir mit dem subject, sprich dem Pattern verglichen und wenn es true ist wird über forEach geschrieben. Passiert das so lange bis die erste Zeile wieder eine Zahl ist aber nicht das Pattern enthält? dann wird so lange nicht geschrieben bis wieder eine Zeile mit Zahl und Pattern gefunden wird?

Dann noch mal eine persönliche Frage 😛 wie kommt man an so viel Know-How ... hast Du das studiert? Ich versuche es nebenbei mit Selbststudium seit ca. 1,5 Jahren und merke immer wieder das es ein soooooo länger Weg ist und ich nur Bruchteile kenne ...

Gruß

Ralf
 
Ich verstehe im Moment noch nicht ganz wie Du den ganzen Block erkennst
Das ist ganz einfach: ein Block beginnt immer mit einer Zeile, deren erstes Zeichen eine Ziffer ist.

Stößt der Filter nun auf einen solchen Blockanfang, wird entschieden, ob der Block ausgegeben wird. Das Ergebnis dieser Entscheidung merkt sich der Filter in der Instanzvariable writing.

Stößt der Filter dagegen auf andere Zeilen (also Zeilen, die keinen Blockanfang darstellen) wird einfach nur die vorangegangene Entscheidung zurückgegeben.

Dann noch mal eine persönliche Frage 😛 wie kommt man an so viel Know-How ... hast Du das studiert? Ich versuche es nebenbei mit Selbststudium seit ca. 1,5 Jahren und merke immer wieder das es ein soooooo länger Weg ist und ich nur Bruchteile kenne ...
Ich bin ein Kind des C64 🙂 Der erste PC war ein 8086, der auf 8 MHz getaktet war.
 
Ich bin ein Kind des C64 🙂 Der erste PC war ein 8086, der auf 8 MHz getaktet war.
🙂 die guten alten Zeiten ... als ich in die Lehre gekommen bin waren Lochkarten das Eingabe Medium 😛 wobei ich dann den Server Weg beschritten habe und nicht den Weg der Software, darum habe ich mir jetzt auf meine "alten Tage" gedacht das ich mal schaue wie das so funktioniert.

Danke für Deine Erklärungen, ich glaube im Prinzip habe ich es jetzt verstanden, wer es heue Abend mal testen und hoffentlich mit ein paar Debug Ausgaben auch im Detail verstehen.

Gruß

Ralf
 

Neue Themen


Zurück
Oben