Files öffnen

Ich bin gerade dabei ein Programm zu schreiben, welches alle Files eines Verzeichnisses öffnen und nach einem String suchen soll, sowie Unterordner öffnen und deren Files. Gebe ich einen Ordner ohne Unterordner an funktioniert es einwandfrei, jedoch nicht wenn der Ornder unter Ordner hat, hierbei erscheint dann immer die Meldung: FileNotFoundError und dann der Link zu dem Ordner, dabei existiert er. Ich habe leider keine Ahnung warum es nicht funktioniert.
Hier der aktuelle Code;
Java:
public class tech {

    public static void main(String[] args) throws FileNotFoundException {
        String verzName = "C:\\Users\\xyz\\Videos";
        Scanner parse = new Scanner(System.in);
        String searchp = parse.next();
        HashMap files = getPaths(new File(verzName),
                new ArrayList<File>(), searchp);
        if(files == null) return;
        System.out.print("Files that contain your parse\n" +files);
    }

    private static HashMap getPaths(File file, ArrayList<File> list, String string) throws FileNotFoundException {
        HashMap dic = new HashMap();
        if (file == null || list == null || !file.isDirectory())
            return null;
        File[] fileArr = file.listFiles();
        for (File f : fileArr) {
            if (f.isDirectory()) {
                getPaths(f, list, string);
            }
            list.add(f);
        }
            for (File e : list) {
                ArrayList<String> lines = new ArrayList<>();
                Scanner scanner = new Scanner(e);
                int counter = 0;
                try {
                while (scanner.hasNextLine()) {
                    counter++;
                    String a = scanner.nextLine();
                    if (a.contains(string)) {
                        String cint = Integer.toString(counter);
                        lines.add(cint);
                        if (!dic.containsKey(e)) {
                            dic.put(e, lines);
                        }
                        else {
                            dic.replace(e, lines);
                        }
                    }
                }
                }
                catch(Exception d) {
                    d.printStackTrace();
                }
            }

Vielen Dank schon mal
 
Hier noch die Fehler Meldung:
Code:
Exception in thread "main" java.io.FileNotFoundException: C:\Users\xyz\Videos\Captures (Zugriff verweigert)
    at java.base/java.io.FileInputStream.open0(Native Method)
    at java.base/java.io.FileInputStream.open(FileInputStream.java:216)
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
    at java.base/java.util.Scanner.<init>(Scanner.java:639)
    at java_beginnging.tech.getPaths(tech.java:33)
    at java_beginnging.tech.getPaths(tech.java:27)
    at java_beginnging.tech.getPaths(tech.java:27)
    at java_beginnging.tech.main(tech.java:14)
 
Ursache dürfte das hier sein
Java:
            if (f.isDirectory()) {
                getPaths(f, list, string);
            }
            list.add(f); // <-----
Das muss vermutlich in einen else-Zweig.

Denn fügst damit auch Verzeichnisse in die Liste hinzu. Wenn du die mit einem Scanner aufmachen willst, wird das nicht funktionieren. Das heißt, verzeichnise dürfen nicht in der Liste landen.
 
Ursache dürfte das hier sein
Java:
            if (f.isDirectory()) {
                getPaths(f, list, string);
            }
            list.add(f); // <-----
Das muss vermutlich in einen else-Zweig.

Denn fügst damit auch Verzeichnisse in die Liste hinzu. Wenn du die mit einem Scanner aufmachen willst, wird das nicht funktionieren. Das heißt, verzeichnise dürfen nicht in der Liste landen.
Danke jetzt funktionierts
 
@モストウォンテッド den Code kann man aber schon ein wenig anders strukturieren.

Gehen wir mal von "innen nach außen": Du willst eine Datei durchsuchen und eine Liste von Zeilennummern erhalten.
Java:
    public static List<Integer> search(File file, String search) throws IOException {

Jetzt willst Du aber nicht nur eine Datei sondern eine ganze Liste von Dateien durchsuchen. Als Ergebnis willst Du die Zuordnung zwischen Datei und Zeilennummern, was Du über eine Map machst. Kann man machen. Aus Gründen der Typsicherheit ist Map generisch!

Java:
    public static Map<File, List<Integer>> searchAll(List<File> files, String search) {

Ok, jetzt hast Du schon mal den Vorteil, dass Du zwei Methoden hast, die Du unabhängig voneinander testen und unabhängig vom gesamten Vorhaben verwenden kannst.

Als nächstes brauchen wir noch eine Dateiliste, die erzeugst Du rekursiv:
Java:
    public static void findFiles(List<File> root, List<File> found) {

Zack, der Parameter für den Suchtext ist weg. Da der Aufruf nicht so schön ist, spendieren wir noch eine "convinience method":
Java:
    public static List<File> findFiles(File root) {

Insgesamt:
Java:
class Test {
    public static void main(String[] args) {
        String verzName = args[0]; // "C:\\Users\\xyz\\Videos";

        System.out.println("Ermittle Dateien");
        List<File> files = findFiles(new File(verzName));
        System.out.printf("%d Dateien unter %s gefunden.\n", files.size(), verzName);

        System.out.print("Suchtext: ");       
        Scanner parse = new Scanner(System.in);
        String text = parse.next();
       
        System.out.printf("Suche nach %s\n", text);
        Map<File, List<Integer>> results = searchAll(files, text);
        System.out.printf("%s in %d Dateien gefunden: %s\n",
                text, results.size(), results.toString());
    }
   
    public static List<File> findFiles(File root) {
        List<File> files = new ArrayList<>();
        findFiles(root, files);
        return files;
    }
   
    public static void findFiles(File root, List<File> found) {
        if (root == null || root == null || !root.isDirectory())
            return;
   
        for (File file : root.listFiles()) {
            if (file.isDirectory()) {
                findFiles(file, found);
            } else {
                found.add(file);
            }
        }
    }

    public static Map<File, List<Integer>> searchAll(List<File> files, String search) {
        Map<File, List<Integer>> matches = new HashMap<>();
       
        for (File file : files) {
            try {
                List<Integer> matchingLineNumbers = search(file, search);
                if (!matchingLineNumbers.isEmpty()) {
                    matches.put(file, matchingLineNumbers);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
       
        return matches;
    }
   
    public static List<Integer> search(File file, String search) throws IOException {
        ArrayList<Integer> matchingLineNumbers = new ArrayList<>();
       
        try(Scanner scanner = new Scanner(file)) {
            int counter = 0;
            while (scanner.hasNextLine()) {
                counter++;
                String line = scanner.nextLine();
                if (line.contains(search)) {
                    matchingLineNumbers.add(counter);
                }
            }
        }
       
        return matchingLineNumbers;
    }
}

Beispiel:
Code:
java -cp . Test META-INF/

Ermittle Dateien
2 Dateien unter META-INF/ gefunden.
Suchtext: app
Suche nach app
app in 2 Dateien gefunden: {META-INF/application.xml=[2, 20], META-INF/glassfish-application.xml=[2, 3]}

Zur früh abgeschickt...

Ja, das ist etwas mehr Code, wobei hier ein paar Zeilen für zusätzliche Ausgabe und einige zusätzliche Leerzeilen abzuziehen wären. Dafür ist der Code auch wesentlich sauberer, wobei man das noch weiter spinnen könnte.
 
Hi @ ... Das sollte eigentlich funktionieren:

Java:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;

public class TextFilesSearch {
    public static List<File> search(File dir, String fEnding, String fContent) throws IOException {
        return Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS)
                .map(Path::toFile)
                .filter(f -> f.getName().endsWith(fEnding))
                //.filter(TextFilesSearch::isValidUtfBom)
                .filter(f -> isContains(f, fContent))
                .collect(Collectors.toList());
    }

    public static boolean isValidUtfBom(File f) {
        if (f == null || !f.isFile() || !f.canRead()) {
            return false;
        }
        try (FileInputStream is = new FileInputStream(f)) {
            byte[] raw = new byte[3];
            int i = is.read(raw);
            if (i < 2) {
                return false;
            }
            if (i == 2) {
                return raw[0] == (byte) 0xFE && raw[1] == (byte) 0xFF || raw[0] == (byte) 0xFF && raw[1] == (byte) 0xFE;
            }
            return  raw[0] == (byte) 0xEF && raw[1] == (byte) 0xBB && raw[2] == (byte) 0xBF ||
                    raw[0] == (byte) 0xFE && raw[1] == (byte) 0xFF ||
                    raw[0] == (byte) 0xFF && raw[1] == (byte) 0xFE;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static boolean isContains(File f, String fContent) {
        try (Scanner scan = new Scanner(f)) {
            while (scan.hasNextLine()) {
                String line = scan.nextLine();
                if (line.contains(fContent)) {
                    return true;
                }
            }
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static void main(String[] args) throws IOException {
        System.out.println(search(new File("dir"), "txt", "teeext"));
    }
}

Die Zeile 16 kannst du, je nach dem in welcher Gestalt deine Textdateien sind, ein- oder aus kommentieren... Pass aber mit sehr großen Textdateien auf, diese könnten die Anwendung verlangsamen.

Das funktioniert bei mir ganz gut. Leider gibt es den Command "file -i" in Windows nicht. 🙁
 
@deppo, der Code tut nicht, was er tun soll: Zeilennummern ausgeben. Außerdem liefert walk auch Directories zurück. Und wenn schon nio (EDIT: was natürlich zu bevorzugen wäre), dann doch konsequent:
Java:
    public static boolean isContains(Path path, String fContent) {
        return Files.lines(path).anyMatch(line -> line.contains(fContent));
    }
 
Woher soll ich denn wissen, was der soll, wenn das nicht vernünftig angegeben ist...
Also Du sagst, dass Du nicht verstehst, was der TE in seinem Code genau machen möchte ... Aber Du hast eine neue Lösung für ihn?

Und das, wo der Code vom TE selbst schon fast ok war, das eigentliche Problem direkt in #3 gefunden und die Lösung in #4 bestätigt wurde?
Dein Vorschlag war jedenfalls total daneben.
Also @mihe7 hat sich auf jeden Fall mit dem Code beschäftigt, versucht zu verstehen, was der TE möchte um dann konstruktive Verbesserungsvorschläge zu bringen.

Ja woraufhin ja auch gefiltert wird.
Öhm ... nein? Zumindest auf den ersten Blick ist das nicht der Fall. Du hast
  • ein Filter auf die Endung - aber das kann auch bei einem Verzeichnis der Fall sein.
  • Eine Prüfung bei dem UTF BOM - das ist aber von dir auskommentiert ...

Aber soll mir auch egal sein ... ich bin wieder raus....
 
Er hat halt nicht gesagt, welches Format seine plain text files haben, welche Dateiendungen, wonach er genau sucht und wie die Rückgabe sein soll.

5, setzen, hätte man früher in der Schule dazu gesagt.
 
Hier nochmal für mich "ordentlich":

Java:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

public class TextFilesSearch {
    public static Map<File, List<Integer>> search(File dir, String fEnding, String fContent) throws IOException {
        return Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS)
                .map(Path::toFile)
                .filter(f -> isValidFile(f, fEnding))
                //.filter(TextFilesSearch::isValidUtfBom)
                .reduce(new HashMap<File, List<Integer>>(), (map, f) -> {
                    List<Integer> lines = getLines(f, fContent);
                    if (!lines.isEmpty()) {
                        map.put(f, getLines(f, fContent));
                    }
                    return map;
                }, (m1, m2) -> {
                    m1.putAll(m2);
                    return m1;
                });
    }

    public static boolean isValidFile(File f, String fEnding) {
        return f != null && f.isFile() && f.canRead() && f.getName().endsWith(fEnding);
    }

    public static boolean isValidUtfBom(File f) {
        try (FileInputStream is = new FileInputStream(f)) {
            byte[] raw = new byte[3];
            int i = is.read(raw);
            if (i < 2) {
                return false;
            }
            if (i == 2) {
                return raw[0] == (byte) 0xFE && raw[1] == (byte) 0xFF || raw[0] == (byte) 0xFF && raw[1] == (byte) 0xFE;
            }
            return  raw[0] == (byte) 0xEF && raw[1] == (byte) 0xBB && raw[2] == (byte) 0xBF ||
                    raw[0] == (byte) 0xFE && raw[1] == (byte) 0xFF ||
                    raw[0] == (byte) 0xFF && raw[1] == (byte) 0xFE;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static List<Integer> getLines(File f, String fContent) {
        List<Integer> lines = new ArrayList<>();
        try (Scanner scan = new Scanner(f)) {
            int i = 0;
            while (scan.hasNextLine()) {
                String line = scan.nextLine();
                i++;
                if (line.contains(fContent)) {
                    lines.add(i);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lines;
    }

    public static void main(String[] args) throws IOException {
        System.out.println(search(new File("Desktop"), "txt", "eingezahlt"));
    }
}

Ihr dürft natürlich Kritik äußern.
 
Er hat halt nicht gesagt, welches Format seine plain text files haben, welche Dateiendungen, wonach er genau sucht und wie die Rückgabe sein soll.

5, setzen, hätte man früher in der Schule dazu gesagt.
Wozu sollte er auch noch diese zusätzlichen Details liefern? Er hat einen bestimmten Code und ein ganz konkretes Problem. Das hat er so gut beschrieben, dass ihm direkt eine Lösung angeboten werden konnte und diese Lösung wurde von TE auch direkt bestätigt. Daher sehe ich hier erst einmal keinerlei Grund, da irgend etwas schlecht zu bewerten. Und ein "5, setzen" kann ich da auch in keiner Weise erkennen.

Wie Du da auf diese komische Wertung oder Sichtweise kommst, entzieht sich mir gerade komplett. Ich finde es ja toll, dass Du so Problemstellungen für Dich als Anreiz siehst, da Deinen eigenen Code zu schreiben. Aber evtl. willst Du Dir überlegen, dafür dann eigene Threads zu erstellen? Denn das Thema war mit #4 eigentlich erledigt. #5 war noch ein Verbesserungsvorschlag an den TE um den TE noch mit etwas mehr Rückmeldung generell weiter zu helfen. Aber ab da sehe ich keine wirkliche Relevanz zu der Fragestellung / des Problems des TE, so dass eben ein eigener Thread bezüglich Rückmeldungen sinnvoll wäre.

Ihr dürft natürlich Kritik äußern.
Ich denke, da verzichte ich lieber ... Deine Umgangsformen hier zeugen nicht wirklich von Sachlichkeit. Daher werde ich mich hüten, weitere Aussagen zu Deinem Code zu machen. Aber es gibt paar Auffälligkeiten bei denen man auch ohne große Diskussion einfache Hinweise auf Kapitel in Joshua Blochs "Effective Java" Buch geben könnte.
 

Zurück
Oben