0

I guess this comes down to reading and writing to the same file. I would like to be able to return the same text file as is input, but with all integer values quadrupled. Should I even be attempting this with Java, or is it better to write to a new file and overwrite the original .txt file?

In essence, I'm trying to transform This:

12
fish
55 10 yellow 3

into this:

48
fish
220 40 yellow 12

Here's what I've got so far. Currently, it doesn't modify the .txt file.

import java.io.*;
import java.util.Scanner;

public class CharacterStretcher 
{
public static void main(String[] args)
{
    Scanner keyboard = new Scanner( System.in );
    System.out.println("Copy and paste the path of the file to fix");
    // get which file you want to read and write
    File file = new File(keyboard.next());
    File file2 = new File("temp.txt");
    BufferedReader reader;
    BufferedWriter writer;
    try {
        // new a writer and point the writer to the file
        FileInputStream fstream = new FileInputStream(file);
        // Use DataInputStream to read binary NOT text.
        reader = new BufferedReader(new InputStreamReader(fstream));
        writer = new BufferedWriter(new FileWriter(file2, true));

        String line = "";
        String temp = "";
        int var = 0;
        int start = 0;
        System.out.println("000");
        while ((line = reader.readLine()) != null) 
        {
            System.out.println("a");
            if(line.contains("="))
            {
                System.out.println("b");
                var = 0;
                temp = line.substring(line.indexOf('='));
                for(int x = 0; x < temp.length(); x++)
                {
                    System.out.println(temp.charAt(x));
                    if(temp.charAt(x)>47 && temp.charAt(x)<58)  //if 0<=char<=9 
                    {
                        if(start==0)
                            start = x;
                        var*=10;
                        var+=temp.indexOf(x)-48;    //converts back into single digit
                    }
                    else
                    {
                        if(start!=0)
                        {
                            temp = temp.substring(0, start) + var*4 + temp.substring(x);
                            //writer.write(line.substring(0, line.indexOf('=')) + temp);
                            //TODO:  Currently writes a bunch of garbage to the end of the file, how to write in the middle?
                        //move x if var*4 has an extra digit
                            if((var<10 && var>2)
                                    || (var<100 && var>24)
                                    || (var<1000 && var>249)
                                    || (var<10000 && var>2499))
                                x++;
                        }
                        //start = 0;
                    }
                    System.out.println(temp + " " + start);
                }
                if(start==0)
                    writer.write(line);
                else
                    writer.write(temp);

            }
        }
        System.out.println("end");
        // writer the content to the file
        //writer.write("I write something to a file.");

        // always remember to close the writer
        writer.close();
        //writer = null;
        file2.renameTo(file); //TODO: Not sure if this works...
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130

3 Answers3

4

Given that this is a pretty quick and simple hack of a formatted text file, I don't think you need to be too clever about it.

Your logic for deciding whether you are looking at a number is pretty complex and I'd say it's overkill.

I've written up a basic outline of what I'd do in this instance. It's not very clever or impressive, but should get the job done I think. I've left out the overwriting and reading the input form the console so you get to do some of the implementation yourself ;-)

import java.io.*;

public class CharacterStretcher {

    public static void main(String[] args) {

        //Assumes the input is at c:\data.txt
        File inputFile = new File("c:\\data.txt");
        //Assumes the output is at c:\temp.txt
        File outputFile = new File("c:\\temp.txt");
        try {
            //Construct a file reader and writer
            final FileInputStream fstream = new FileInputStream(inputFile);
            final BufferedReader reader = new BufferedReader(new InputStreamReader(fstream));
            final BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile, false));

            //Read the file line by line...
            String line;
            while ((line = reader.readLine()) != null) {
                //Create a StringBuilder to build our modified lines that will
                //go into the output file
                StringBuilder newLine = new StringBuilder();

                //Split each line from the input file by spaces
                String[] parts = line.split(" ");

                //For each part of the input line, check if it's a number
                for (String part : parts) {
                    try {
                        //If we can parse the part as an integer, we assume
                        //it's a number because it almost certainly is!
                        int number = Integer.parseInt(part);
                        //We add this to out new line, but multiply it by 4
                        newLine.append(String.valueOf(number * 4));
                    } catch (NumberFormatException nfEx) {
                        //If we couldn't parse it as an integer, we just add it
                        //to the new line - it's going to be a String.
                        newLine.append(part);
                    }

                    //Add a space between each part on the new line
                    newLine.append(" ");
                }
                //Write the new line to the output file remembering to chop the
                //trailing space off the end, and remembering to add the line
                //breaks
                writer.append(newLine.toString().substring(0, newLine.toString().length() - 1) + "\r\n");
                writer.flush();
            }

            //Close the file handles.
            reader.close();
            writer.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
BunjiquoBianco
  • 1,994
  • 2
  • 21
  • 24
3

You may want to consider one of these:

  1. Build the new file in memory, rather than trying to write to the same file you are reading from. You could use StringBuilder for this.

  2. Write to a new file, then overwrite the old file with the new one. This SO Question may help you there.

With both of these, you will be able to see your whole output, separate from the input file. Additionally, with option (2), you don't have the risk of the operation failing in the middle and giving you a messed up file.

Now, you certainly can modify the file in-place. But it seems like unnecessary complexity for your case, unless you have really huge input files.

At the very least, if you try it this way first, you can narrow down on why the more complicated version is failing.

Community
  • 1
  • 1
jwd
  • 10,837
  • 3
  • 43
  • 67
0

You cannot read and simultaneously write to the same file, because this would modify the text you currently read. This means, you must first write a modified new file and later rename it to the original one. You probably need to remove the original file before renameing.

For renaming, you can use File.renameTo or see one of the many SO's questions

You seem to parse integers in your code by collecting single digits and adding them up. You should consider using either a Scanner.nextInt or employ Integer.parseInt.

You can read your file line by line, split the words at white space and then parse them and check if it is either an integer or some other word.

Community
  • 1
  • 1
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • This is simply untrue. RandomAccessFile is used to interact with a file in Read/Write mode. See http://docs.oracle.com/javase/7/docs/api/java/io/RandomAccessFile.html – Nathaniel Waisbrot Mar 12 '13 at 16:58
  • @NathanielWaisbrot You can certainly modify a file while reading, but the result is not predictable. Ignoring buffering, you will read what was written currently, and this is usually not what you want. – Olaf Dietsche Mar 12 '13 at 17:04
  • It is *possible* to produce unpredictable behavior by overlapping reads and writes, but if one codes carefully and understands synchronization it is really not an issue. One example you may be familiar with is the field of databases, many of which perform concurrent reads and writes to a single file. All you need to do is track control of the file, know the locations that are not currently being written to, and use read/write locks. – Nathaniel Waisbrot Mar 12 '13 at 17:42
  • 1
    @NathanielWaisbrot You read the question, did you? No databases, no fixed length records, just arbitrary length lines. And in that context, you are plain and simply wrong. – Olaf Dietsche Mar 12 '13 at 17:47
  • No, a database was an example that I was providing to disprove your unconditional claim that opening a file for reading and writing is impossible. The question does not provide enough information to determine if it's reasonable to do simultaneous reads and writes, and jwd is correct to suggest that it's a needlessly complex thing to do. But to claim that this *cannot be done*, which is what you wrote, is wrong. – Nathaniel Waisbrot Mar 12 '13 at 18:01
  • Right at title, you can read "... text file". This should already be "enough information to determine, if it's reasonable to do simultaneous reads and writes". Shortly after, the OP provided Java code, which made it completely clear. And now to my answer. You shouldn't stop reading at the first comma, really. – Olaf Dietsche Mar 12 '13 at 19:55
  • Uh, trolling on SO ? I need some popcorns... :P – Andrea Ligios Mar 13 '13 at 14:37
  • @Nathaniel, AndreaLigios You're right, I shouldn't do that. Sorry to everybody and my apologies to Nathaniel. – Olaf Dietsche Mar 13 '13 at 14:45