0

I need to create an application that adds some suffix to some file name before the file extension. The application takes one obligatory argument - the path to a config file. I did a config.properties file whith value/key:

mode=copy (keep the source file) suffix=abc files=change.txt:further.txt:yandex.txt (a list of files for suffixing. File paths are separated with column:.)

For log a message I use java.util.logging.

  • if mode from config is not recognized, log Mode is not recognized: <mod_input_value> at SEVERE level and stop the execution. Example: Mode is not recognized: copi
  • if suffix is not set, log No suffix is configured at SEVERE level and stop the execution.
  • if files are not specified, log No files are configured to be copied/moved at WARNING level and stop the execution.
  • if one of the specified files does not exist, log No such file: <file-path> at SEVERE level, but do not stop the processing of other files. Note that a file path in the message must contain not backslashes but forward slashes ('/') to separate the path parts. Example: No such file: src/test/resources/no-such-file.txt
  • When copying a file, log <source-file> -> <destination-file> at INFO level. Note, that file path in the message must contain not backslashes but forward slashes (/) to separate path parts, not backslashes. Example: src/test/resources/file.txt -> src/test/resources/file-suffix.txt

I made the following code:

    public class Suffixing {
        public static String PATH_TO_PROPERTIES = "src/main/resources/config.properties";
    
        public static void main(String[] args) throws IOException {
    
            FileInputStream fileInputStream;
            Logger logging = Logger.getLogger(Suffixing.class.getName());
            Properties prop = new Properties();
    
            fileInputStream = new FileInputStream(PATH_TO_PROPERTIES);
            prop.load(fileInputStream);
            
            String mode = prop.getProperty("mode");
            String suffix = prop.getProperty("suffix");
            String files = prop.getProperty("files");

            File one = new File("D:/map/test/change.txt");
            File two = new File("D:/map/test/further.txt");
            File three = new File("D:/map/test/yandex.txt");
            for (String file : files.split(":")) {
    
                if (mode != "copy") {
                    logging.log(Level.SEVERE, "Mode is not recognized: " + mode);
                    fileInputStream.close();
                } else if (prop.getProperty(suffix) == "") {
                    logging.log(Level.SEVERE, "No suffix is configured");
                    fileInputStream.close();
                } else if (prop.getProperty("files") == "") {
                    logging.log(Level.WARNING, "No files are configured to be copied/moved");
                    fileInputStream.close();
                } else if (!one.exists() || !two.exists() || !three.exists()) {
                    logging.log(Level.SEVERE, "No such file: ");
                } else {
    
                    int at = file.indexOf('.');
                    String newFile = file.substring(0, at) + suffix + file.substring(at);
                    File dest = new File("D:/map/test" + newFile);
                    logging.log(Level.INFO, prop.getProperty("files") + "-->" + dest);
                }
            }
    
    
        }
    }

For some inputs the code is working incorrectly, what do I need to modify?

  • `mode != "copy"` is not how you do `String` comparison, use `String#equals` instead – MadProgrammer Oct 06 '21 at 21:24
  • You shouldn't reference `src` with in your code. If the files are contained within your application context, they are likely not going to be writable and can't be accessed as "files" – MadProgrammer Oct 06 '21 at 21:34
  • "For some inputs": such as what? "... the code is working incorrectly": such as how? – user207421 Oct 07 '21 at 05:37

2 Answers2

1

Don't compare Strings with ==. You should always use equals() instead. Read more at How do I compare strings in Java?.

Having said that, try the following:

public class Suffixing {
    public static String PATH_TO_PROPERTIES = "src/main/resources/config.properties";

    public static void main(String[] args) throws IOException {
        FileInputStream fileInputStream;
        Logger logging = Logger.getLogger(Suffixing.class.getName());
        Properties prop = new Properties();

        fileInputStream = new FileInputStream(PATH_TO_PROPERTIES);
        prop.load(fileInputStream);
        
        String mode = prop.getProperty("mode");
        String suffix = prop.getProperty("suffix");
        String files = prop.getProperty("files");

        File one = new File("D:/map/test/change.txt");
        File two = new File("D:/map/test/further.txt");
        File three = new File("D:/map/test/yandex.txt");
        for (String file : files.split(":")) {
            if (!Objects.equals(mode, "copy")) {
                logging.log(Level.SEVERE, "Mode is not recognized: " + mode);
                fileInputStream.close();
            } else if (prop.getProperty(suffix).isBlank()) {
                logging.log(Level.SEVERE, "No suffix is configured");
                fileInputStream.close();
            } else if (prop.getProperty("files").isBlank()) {
                logging.log(Level.WARNING, "No files are configured to be copied/moved");
                fileInputStream.close();
            } else if (!one.exists() || !two.exists() || !three.exists()) {
                logging.log(Level.SEVERE, "No such file: ");
            } else {
                int at = file.indexOf('.');
                String newFile = file.substring(0, at) + suffix + file.substring(at);
                File dest = new File("D:/map/test" + newFile);
                logging.log(Level.INFO, prop.getProperty("files") + "-->" + dest);
            }
        }
    }
}
João Dias
  • 16,277
  • 6
  • 33
  • 45
1

If you want to stop execution at first error, you would be better off by changing all the error logging like this:

logging.log(Level.SEVERE, "Mode is not recognized: " + mode);

to throw RuntimeException (or whatever suitable exception class you pick) such as:

throw new RuntimeException("Mode is not recognized: " + mode);

You should tidy your file handling, loading properties cleanly:

Properties prop = new Properties();
try(var in = new FileInputStream(PATH_TO_PROPERTIES)) {
    prop.load(in);
}
String mode = prop.getProperty("mode");
String suffix = prop.getProperty("suffix");
String files = prop.getProperty("files");

It does not make sense to do all those checks inside the loop because they won't be executed unless "files" is set, so pull these out of the for loop:

if (!Objects.equals(mode, "copy"))
    logging.log(Level.SEVERE, "Mode is not recognized: " + mode);
if (suffix == null || suffix.isBlank()) {
    logging.log(Level.SEVERE, "No suffix is configured");
}
if (files == null || files.isBlank()) {
    logging.log(Level.WARNING, "No files are configured to be copied/moved");
}

Its not clear why you need one/two/three and this line if the files are read from config.properties:

if (!one.exists() || !two.exists() || !three.exists()) {
     logging.log(Level.SEVERE, "No such file: ");

The loop over "files" should use lastIndexOf() in case there are dots in the directory names.

for (String file : files.split(":")) {
    File f = new File(file);
    if (!f.exists()) {
        logging.log(Level.SEVERE, "No such file: "+f);
    } else {
        int at = file.lastIndexOf('.');
        String newFile = file.substring(0, at) + "-" + suffix + file.substring(at);
        File dest = new File(newFile);
        logging.log(Level.INFO, f + "-->" + dest);
    }
}

The split(":") won't work for Windows paths with drive letters, but you have covered that issue in another question.

DuncG
  • 12,137
  • 2
  • 21
  • 33