4
\$\begingroup\$

So, given a file with the following format:

[header]
line of data
line of data
line of data
line of data

[header 2]
line of data
line of data
line of data

...

I add a line of data to a specific header so the result would be:

...
[target header]
line of data
...
new line inserted

The program currently only adds lines but is written so it accepts an input file that lists instructions with the format instruction|[header]|line to add e.g. A|[Passions]|Code Review would add Code Review to the Passions section.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Scanner;
public class AdjustList {
 public static void main(String[] args) {
 if (args.length != 1) {
 System.err.println("No arguments provided.");
 System.exit(1);
 }
 try (Scanner fileScanner = new Scanner(new File(args[0]))) {
 while (fileScanner.hasNextLine()) {
 String[] commandParameters = fileScanner.nextLine().split("\\|");
 if (commandParameters.length != 3) {
 throw new IllegalArgumentException("Invalid parameter format");
 }
 File targetFile = new File("ImportantList.md");
 processCommand(targetFile, commandParameters[0], commandParameters[1], commandParameters[2]);
 }
 } catch (FileNotFoundException fnfe) {
 System.err.println("File doesn't exist / wrong directory");
 }
 }
 private static void processCommand(File file, String instruction, String targetSection, String inputLine) {
 boolean taskComplete = false;
 StringBuilder fileBuilder = new StringBuilder();
 try (Scanner fileScanner = new Scanner(file)) {
 if (instruction.equals("A")) { // add
 System.out.println("Adding " + inputLine + " to " + targetSection);
 while (fileScanner.hasNextLine()) {
 String line = fileScanner.nextLine();
 if (line.equals(targetSection)) {
 fileBuilder.append(line).append('\n');
 while (!taskComplete) {
 line = fileScanner.nextLine();
 if (line.isEmpty()) {
 fileBuilder.append(inputLine).append('\n');
 taskComplete = true;
 } else {
 fileBuilder.append(line).append('\n');
 }
 }
 } else {
 fileBuilder.append(line).append('\n');
 }
 }
 }
 } catch(FileNotFoundException fnfe) {
 System.err.println("File doesn't exist / wrong directory");
 System.exit(1);
 }
 writeOutput(file, fileBuilder.toString());
 }
 private static void writeOutput(File file, String output) {
 try (PrintWriter writer = new PrintWriter(file, "UTF-8")) {
 writer.write(output);
 } catch (FileNotFoundException | UnsupportedEncodingException ex) {
 ex.printStackTrace();
 } 
 }
}

The file is read, line by line, storing the input into a StringBuilder with the additional line added based on a flag. This works but I get the feeling it's not the cleanest way.

asked Jun 20, 2016 at 16:09
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Input validation

It looks like if instruction is not "A", then you will be overwriting "ImportantList.md" with the contents of an empty StringBuilder.

Iterable-based processing

If the file sizes you are dealing with are relatively small enough to fit contents in memory, you can consider reading them in as a List, do the required processing, then write it out via Files.write(Path, Iterable, Charset, OpenOption). This avoids having to concatenate \n repetitively while using the StringBuilder. For example:

private static void process(Path path, String targetHeader, String newLine) {
 List<String> lines = null;
 try {
 lines = Files.readAllLines(path, StandardCharsets.UTF_8);
 } catch (IOException e) {
 // handle error here
 }
 int index = lines.indexOf(targetHeader);
 if (index == -1) {
 // log that target header is not found?
 return;
 }
 int i = index + 1;
 for (; i < lines.size(); i++) {
 if (lines.get(i).isEmpty()) {
 lines.add(i, newLine);
 break;
 }
 }
 if (i == lines.size()) {
 lines.add(newLine);
 }
 try {
 Files.write(path, lines, StandardCharsets.UTF_8);
 } catch (IOException e) {
 // handle error here
 } 
}

Here, we also handle the case where the target header is the last header and there is no trailing newline at the end of the text file, using the comparison i == lines.size().

answered Jun 22, 2016 at 16:35
\$\endgroup\$
2
\$\begingroup\$

Misleading Message?

 if (args.length != 1) {
 System.err.println("No arguments provided.");
 System.exit(1);
 }

So if I have 2 arguments, I get the message No arguments provided. Umm... I provided 2 arguments!

Suggested fix:

Change the above code to:

 if (args.length == 0) {
 System.err.println("No arguments provided.");
 System.exit(1);
 }

And you can possible warn the user about only requiring one argument if they provide too much. Something like:

 if (args.length > 1) {
 System.out.println("Warning! Too many arguments; only the first one will be considered.");
 }
answered Jun 20, 2016 at 21:52
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.