2
\$\begingroup\$

I'm attempting to learn more about Java and have created a method that takes a text file with stdout (space separated file) and converts it to a CSV file. I was attempting to use standard Java SE version 8.

Is there a better, more efficient, way of doing this?

The logic is:

  1. Open file
  2. Read file by line into string so it can be split
  3. Split string removing spaces, back into array
  4. Join with StringJoiner using ,
  5. Convert back to string to remove leading ,
  6. Update final array to be returned

Method to open file:

public void OpenFile(String fileName)
{
    try
    {
        subFile = new Scanner (new File(fileName));
    }
    catch (Exception e)
    {
        System.out.println("File dosn't exist.");
    }
}

Method to convert:

    public String[] TextToCsvArray(String[] fileArray)
{
    int i=0;
    while(subFile.hasNext())
    {
        String line = subFile.nextLine();            
        String[] split = line.split("\\s+");            
        StringJoiner joiner = new StringJoiner(",");

        for (String strVal: split)
            joiner.add(strVal);

        line = joiner.toString();
        line = line.startsWith(",") ? line.substring(1) : line;
        fileArray[i++] = line;            
    }
    return fileArray;
}
\$\endgroup\$

migrated from stackoverflow.com Nov 14 '16 at 3:45

This question came from our site for professional and enthusiast programmers.

  • \$\begingroup\$ I will do the same way that you do, except there will be bugs since you are mutating params fileArray and you don't know the size of the array :) \$\endgroup\$ – Hendrik T Nov 13 '16 at 3:59
3
\$\begingroup\$

Since you are using Java 8 it is good to use the great streaming methods it give you. You can write your code simply like the following:

 public static void main(String[] args) {
    String fileName = "./a.txt";
    try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
        String result = stream.map(s -> s.split("\\s+"))
                              .map(s -> Arrays.stream(s).collect(Collectors.joining(","))+"\n")
                              .collect(Collectors.joining());
        System.out.println(result);

    } catch (IOException e) {
        e.printStackTrace();
    }

The final result is stored in result and you just need simply to write it into the file!

\$\endgroup\$
  • \$\begingroup\$ Thanks Guys, all these answers have helped me gain more understanding, wasn't aware of a number of features that have been suggested... thanks for the advice. :) \$\endgroup\$ – Graham Nov 13 '16 at 9:09
  • \$\begingroup\$ Pooya, If I needed to remove the first "," off each line much like: line = line.startsWith(",") ? line.substring(1) : line; how would you suggest to put it into the stream.map command??? \$\endgroup\$ – Graham Nov 13 '16 at 23:33
  • \$\begingroup\$ @Graham: in the second map statement you can put your logic although it may look bit more complicated and probably cannot fit in single lambda expression \$\endgroup\$ – Pooya Nov 14 '16 at 1:36
3
\$\begingroup\$

If your input is already separated correctly by spaces, it seems all you need to do is to convert those into commas and you're good. I'm not sure you need to go to/from arrays.

I would replace the code inside the loop:

{
    String line = subFile.nextLine();            
    String[] split = line.split("\\s+");            
    StringJoiner joiner = new StringJoiner(",");

    for (String strVal: split)
        joiner.add(strVal);

    line = joiner.toString();
    line = line.startsWith(",") ? line.substring(1) : line;
    fileArray[i++] = line;            
}

with this:

{
    String line = subFile.nextLine();            
    line.trim().replaceAll(" +", " "); //check for double spaces
    line.replace(' ', ',');   //replace space with comma
    fileArray[i++] = line; 
}

Oh, and check for the array size like someone else mentioned.

\$\endgroup\$
  • \$\begingroup\$ Come to think of it, you could probably consolidate the 2 replace lines also: \$\endgroup\$ – TDWebDev Nov 13 '16 at 6:07
  • \$\begingroup\$ I like the combination of triming and replacing here, thanks for the tips :) \$\endgroup\$ – Graham Nov 13 '16 at 9:10
1
\$\begingroup\$

Question: is there a better, more efficent, way of doing this...?

At what point do you call Scanner.close()? When you're dealing with input streams, you're supposed to close them when you're done.

For this reason, I'm not crazy about breaking OpenFile into a separate method... at least not in that way.

It's good to break big chunks of logic into smaller, more manageable bits, but try something like this approach instead...

public Scanner openFile(String fileName) {
    try {
        return new Scanner(new File(fileName));
    } catch (Exception e) {
        throw new IllegalArgumentException("Specified file doesn't exist:  " + fileName);
    }
}

But as far as closing your streams -- I like try with resources.

try (Scanner scanner = openFile(filename)) {
    // do your stuff...
}
\$\endgroup\$
  • \$\begingroup\$ Thanks Drew, forgot I could use scanner and file like this, and returning it the same line apperares far more efficient. Cheers \$\endgroup\$ – Graham Nov 13 '16 at 9:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.