Как заставить мое приложение читать мой файл, когда он выбран, и когда пользователь выбирает папку, а затем заставляет приложение читать все файлы в ней? - PullRequest
0 голосов
/ 14 апреля 2020

Я просто пытаюсь создать приложение Java Swing, которое читает шаблон из файла и сканирует или сопоставляет шаблоны .... Это пока что созданный ActionListener, но он не будет читать файлы каких-либо папок. , Может ли кто-нибудь помочь мне решить эту проблему?


    public static class loadListener implements ActionListener{
            @Override
            public void actionPerformed(ActionEvent e) {
                // ... Point the current directory.
                JFileChooser fileChooser = new JFileChooser(".//");
                fileChooser.showOpenDialog(null);
                // ... Get the selected file
                File file = fileChooser.getSelectedFile();
                if (file != null) {
                    setFile(file);
                    setUserPromptLabel(file.getName());
                }
            }
    }

    public static void setFile(File file) {
        fileBytesArray = readFile(file);
    }

    public static void setUserPromptLabel(String infoTxt) {
        panel.userPromptLabel.setText(infoTxt);
    }

    public static ArrayList<Byte> readFile(File file) {
        ArrayList<Byte> fileBytes = new ArrayList<>();
        try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
            int nextByte;
            byte currentByte;
            // ... loop and store the byte in fileBytes
            while ((nextByte = is.read()) != -1) {
                currentByte = (byte) nextByte;
                fileBytes.add(currentByte);
            }
        } catch (FileNotFoundException e) {
            System.out.println("File not found");
        } catch (IOException e) {
            System.out.println("Error: " + e.getMessage());
        }
        return fileBytes;
    }

Это мой код для чтения файла. Кто-нибудь может мне помочь в этом?

Ответы [ 2 ]

0 голосов
/ 20 апреля 2020
  1. Являются ли файлы большими (например, более 2 ГБ каждый) или маленькими?
  2. Какая кодировка используется в файлах?
  3. Существует ли конкретное c расширение имен файлов для search?
  4. Является ли шаблон поиска простым строковым литералом или регулярным выражением?
  5. Можно ли анализировать строку за строкой или шаблон содержит символы новой строки?
  6. Что вы хотите сделать с соответствующими файлами? Вернуть их все, вернуть только в первый раз или просто вернуть флаг, чтобы указать, что он был найден?
  7. Что вы хотите сделать с несоответствующими файлами?
  8. Хотите выполнить поиск? имена путей к каталогам / файлам themsevles?
  9. Хотите отфильтровать нетекстовые файлы или нет?

Я реализовал поисковый код, который отвечает на поставленные выше вопросы, например так:

  1. Маленький.
  2. UTF-8 по умолчанию, но может использовать любой Charset.
  3. При желании можно указать включенные расширения или исключенные из поиска.
  4. Может быть одним из них.
  5. Вы не разбираете построчно. Это делает файлы небольшими, но позволяет искать шаблоны с символами новой строки.
  6. Возвращать набор, содержащий все сопоставленные файлы.
  7. Игнорировать их.
  8. Нет. Только содержимое файла. Но вы можете использовать тот же лог c для имен путей (ie сканировать их как String объекты с Scanner).
  9. Опционально (указав их расширения как в 3).

Код:

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
import java.util.Scanner;
import java.util.regex.Pattern;

public class Searcher {

    public static class Builder {
        private String pattern;
        private int patternFlags;
        private Charset charset;
        private FileFilter filter;
        private Iterable<String> extentions;
        private boolean extentionsInclusives;
        private Locale caseInsenstivityExtentionLocale;
        private short maxDepth;

        public Builder() {
            pattern = null;
            patternFlags = 0;
            charset = StandardCharsets.UTF_8;
            filter = null;
            extentions = Collections.emptyList();
            extentionsInclusives = false;
            caseInsenstivityExtentionLocale = Locale.getDefault();
            maxDepth = -1;
        }

        /**
         * Specifies the {@code Pattern} used to check against the files while searching. Here you
         * specify a regular expression instead of a literal {@code String} and also supply the
         * {@code Pattern} flags you want (according to {@link Pattern#compile(java.lang.String, int)}
         * method). The default value is not set.
         * @param regex
         * @param flags
         * @return 
         * @see #literal(java.lang.String)
         */
        public Builder regex(final String regex, final int flags) {
            pattern = regex;
            patternFlags = flags;
            return this;
        }

        /**
         * Specifies the {@code Pattern} used to check against the files while searching. Here you
         * specify a literal {@code String} to be used instead of a regular expression. The default
         * value is not set.
         * @param s
         * @return 
         * @see #regex(java.lang.String, int)
         */
        public Builder literal(final String s) {
            pattern = Pattern.quote(s);
            patternFlags = 0;
            return this;
        }

        /**
         * The default value is {@link StandardCharsets#UTF_8}.
         * @param charset The {@code Charset} the files will be decoded with, in order to scan for the search pattern.
         * @return 
         */
        public Builder charset(final Charset charset) {
            this.charset = charset;
            return this;
        }

        /**
         * Specifies a {@code FileFilter} to be used when listing the files and subdirectories of a
         * directory (used only when the {@link #depth(short) depth} allows subdirectory searching,
         * ie is not equal to zero). Supply {@code null} in order to not use a particular filter.
         * The default value is {@code null}.
         * @param filter
         * @return 
         * @see #depth(short)
         */
        public Builder filter(final FileFilter filter) {
            this.filter = filter;
            return this;
        }

        /**
         * Specifies the file extentions of files to be checked. For example, if one wants to include
         * nothing but only files with {@code "txt"} extention, then should call this method with
         * the first argument to {@code true} and then the literal {@code "txt"}. Extentions are
         * always plain literal {@code String}s (without beginning with the dot character) and not
         * regular expressions. For another example, if one wants to exclude nothing but only files
         * with {@code "png"} and {@code "jpg"} extentions, then should call this method with the
         * first argument to {@code false} and then the literals {@code "png"} and {@code "jpg"}. If
         * one wants to include every file, no matter what extention it has, then he should call
         * this method with an empty array of extentions and {@code false} for the first argument
         * (something like <i>excluding the nothing</i>, ie <i>include everything</i>). The default
         * value is to include everything. Refer to {@link #extentionCaseInsenstivityLocale(java.util.Locale)}
         * to specify whether the extentions will be checked as case sensitive or not.
         * @param inclusives
         * @param extentions
         * @return 
         * @see #extentionCaseInsenstivityLocale(java.util.Locale)
         */
        public Builder extentions(final boolean inclusives, final String... extentions) {
            this.extentions = new HashSet<>(Arrays.asList(extentions));
            extentionsInclusives = inclusives;
            return this;
        }

        /**
         * Specifies whether the extentions specified by {@link #extentions(boolean, java.lang.String...)}
         * are case sensitive or not. Use any non-null {@code Locale} to make them case insensitive.
         * Use {@code null} to make the extentions case sensitive. The default value is the
         * {@link Locale#getDefault() default Locale} (which means the extentions are case
         * insensitive by default).
         * @param locale
         * @return 
         * @see #extentions(boolean, java.lang.String...)
         */
        public Builder extentionCaseInsenstivityLocale(final Locale locale) {
            this.caseInsenstivityExtentionLocale = locale;
            return this;
        }

        /**
         * Specifies the <b>maximum</b> depth the recursion in subdirectories will take place while
         * searching for the pattern. Any negative value means there is not limit to the depth of
         * the recursion. A value of zero means that only the given file in
         * {@link Searcher#search(java.io.File) the search method} will be checked. A value of
         * {@code 1} means that the given path will be recursed once (if it is a directory), ie the
         * given path is a file so it will be scanned, or the given path is a directory in which
         * case the files inside it (and only) will be scanned.
         * @param d
         * @return 
         */
        public Builder depth(final short d) {
            maxDepth = d;
            return this;
        }

        /**
         * Builder's state is preserved.
         * @return the newly created {@code Searcher}.
         */
        public Searcher build() {
            Objects.requireNonNull(pattern, "Pattern is not set. You must call at least once the method 'regex(...)' or the method 'literal(...)'.");
            return new Searcher(Pattern.compile(pattern, patternFlags), charset, filter, extentions, extentionsInclusives, caseInsenstivityExtentionLocale, maxDepth);
        }
    }

    private static String getFilePathNameExtention(final String path) {
        final int dotI = path.lastIndexOf('.'),
                  sepI = path.lastIndexOf(File.separatorChar);
        if (sepI < dotI)
            return path.substring(dotI + 1);
        return "";
    }

    private final Pattern pattern;
    private final FileFilter filter;
    private final String charset;
    private final Locale caseInsenstivityExtentionLocale;
    private final HashSet<String> extentions;
    private final short maxDepth;
    private final boolean extentionsInclusives;

    public Searcher(final Pattern pattern,
                    final Charset charset,
                    final FileFilter filter, //Can be null, to list everything.
                    final Iterable<String> extentions,
                    final boolean extentionsInclusives, //Indicates whether extentions are inclusives or exclusives.
                    final Locale caseInsenstivityExtentionLocale, //Can be null, for case sensitive extentions.
                    final short maxDepth) { //Negative for no max, zero for only current path, etc...
        this.pattern = Objects.requireNonNull(pattern);
        this.charset = charset.name();
        this.extentions = new HashSet<>();
        if (caseInsenstivityExtentionLocale != null)
            extentions.forEach(extention -> this.extentions.add(extention.toLowerCase(caseInsenstivityExtentionLocale)));
        else
            extentions.forEach(extention -> this.extentions.add(extention));
        this.extentionsInclusives = extentionsInclusives;
        this.filter = filter;
        this.caseInsenstivityExtentionLocale = caseInsenstivityExtentionLocale;
        this.maxDepth = maxDepth;
    }

    protected boolean isExtentionScanableContents(String extention) {
        if (caseInsenstivityExtentionLocale != null)
            extention = extention.toLowerCase(caseInsenstivityExtentionLocale);
        return !(extentionsInclusives ^ extentions.contains(extention)); //XNOR requires equal both sides.
    }

    protected boolean canScanContents(final File file) {
        return file.isFile() && isExtentionScanableContents(getFilePathNameExtention(file.toString()));
    }

    protected boolean canListContents(final File directory, final short currentDepth) {
        return directory.isDirectory() && (maxDepth < 0 || currentDepth < maxDepth);
    }

    protected void search(final File fileOrDirectory, final short currentDepth, final Collection<File> found) throws FileNotFoundException {
        if (canListContents(fileOrDirectory, currentDepth))
            for (final File f: (filter == null? fileOrDirectory.listFiles(): fileOrDirectory.listFiles(filter)))
                search(f, (short) (currentDepth + 1), found);
        if (canScanContents(fileOrDirectory) && (null != new Scanner(fileOrDirectory, charset).findWithinHorizon(pattern, 0)))
            found.add(fileOrDirectory);
    }

    /**
     * Searches the contents of the files in the given path if the path is a directory, or scans the
     * contents of the given path itself if the path is a normal file. All search options are
     * specified at construction time.
     * @param fileOrDirectory
     * @return All the files/paths that contain in their contents the search pattern.
     * @throws FileNotFoundException If the file is successfully listed but then moved and unreachable before its scanning operation takes place.
     */
    public HashSet<File> search(final File fileOrDirectory) throws FileNotFoundException {
        final HashSet<File> found = new HashSet<>();
        search(fileOrDirectory, (short) 0, found);
        return found;
    }
}

Свойства поисковика (и строителя):

  • pattern : шаблон для поиска. Определяется методами regex и literal класса Searcher.Builder (или Pattern непосредственно в конструкторе Searcher).
  • кодировка : кодировка использовать для декодирования файлов. По умолчанию используется UTF-8.
  • filter : фильтрация при выводе списка файлов из каталогов. По умолчанию null, что означает отсутствие фильтра (ie перечислить все).
  • extensions : расширения имен файлов, которые нужно включить или исключить из поиска. По умолчанию используется пустой набор.
  • extentionsInclusives : указывает, включены ли extensions в поиск или исключены из него. По умолчанию это исключение (но с пустым набором, приведенным выше, это означает, что ничего не нужно исключать, ie включить каждый файл).
  • caseInsenstivityExtentionLocale : Locale, который будет использоваться при сравнении нечувствительные к регистру расширения имени файла. По умолчанию это Locale.getDefault, что делает их нечувствительными к регистру для пользователя Locale.
  • глубина : максимальная глубина каталогов, которую нужно достичь. Отрицательное значение без ограничений, нулевое значение только для текущего заданного файла, значение 1 для перечисления файлов данного каталога и т. Д. ...

Как его использовать?

Вы можно просто скопировать и вставить его в java файл с именем Searcher. java, и вы готовы к go.

Я вложил достаточно javadoc в методы класса Searcher.Builder, чтобы дать более подробную информацию.

Вот пример кода о том, как его использовать:

import java.io.File;
import java.io.FileNotFoundException;
import javax.swing.JFileChooser;

public class Main {
    public static void main(final String[] args) {
        final Searcher.Builder builder = new Searcher.Builder();

        final Searcher searcher =
            builder.literal("String to search")
                   .extentions(true, "txt", "java")
                   .build();

        final JFileChooser jfc = new JFileChooser();
        jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        jfc.setMultiSelectionEnabled(false);
        if (JFileChooser.APPROVE_OPTION == jfc.showOpenDialog(null)) {
            final File selectedFile = jfc.getSelectedFile();
            if (selectedFile != null) {
                try {
                    System.out.println("Only txt and java files: " + searcher.search(selectedFile));
                }
                catch (final FileNotFoundException fnfx) {
                    System.err.println("Error: " + fnfx);
                }
            }
            else
                System.err.println("null file.");
        }
        else
            System.out.println("Cancelled.");
    }
}
0 голосов
/ 15 апреля 2020

Улучшения

Не считывайте ваши файлы в ArrayList байтов, просто возвращайте обычный байтовый массив

public static byte[] readFile(File file)
{
  try(FileInputStream fis=new FileInputStream(file))
  {
    byte fullFile[]=new byte[file.length()];
    fis.read(fullFile);
    return fullFile;
  }
 /*return null or exit program incase of IO errors*/
}

Ваш ответ

public static void setFile(File file)
{
 if(file.isDirectory())
 {
  Arrays.asList(file.listFiles())
             .forEach(child->
              {
               byte fileData[]=readFile(child);
               /* Do your pattern matching here or store this file in an 
seperate list*/
              });
 }
 else
 { 
  byte fileData[]=readFile(file);
  /* Your pattern matching here*/
 }
 }
...