0

I have a text file with a sequence of 4194304 letters ranging from A-D all on one line (4 MB). How would I randomly point to a character and replace the following set of characters to another file that is 100 characters long and write it out to a file? I'm actually currently able to do this, but I feel it's really inefficient when I iterate it several times.

Here's an illustration of what I mentioned above: Link to Imageshack

Here's how I'm currently achieving this:

Random rnum = new Random();
FileInputStream fin = null;
FileOutputStream fout = null;
int count = 10000;
FileInputStream fin1 = null;

File file1 = new File("fileWithSet100C.txt");

int randChar = 0;
while(cnt > 0){
    try {
        int c = 4194304 - 100;

        randChar = rnum.nextInt(c);
        File file = new File("file.txt");

                    //seems inefficient to initiate these guys over and over 
        fin = new FileInputStream(file);
        fin1 = new FileInputStream(file1);

        //would like to remove this and have it just replace the original
        fout = new FileOutputStream("newfile.txt");

        int byte_read;
        int byte_read2;

        byte[] buffer = new byte[randChar]; 
        byte[] buffer2 = new byte[(int)file1.length()]; //4m

        byte_read = fin.read(buffer);
        byte_read2 = fin1.read(buffer2);

        fout.write(buffer, 0, byte_read);
        fout.write(buffer2, 0, byte_read2);

        byte_read = fin.read(buffer2);
        buffer = new byte[4096]; //4m
        while((byte_read = (fin.read(buffer))) != -1){
            fout.write(buffer, 0, byte_read);
        }

        cnt--;
    }
    catch (...) {
        ...
    }
    finally {
          ...
    }
    try{
        File file = new File("newfile.txt");
        fin = new FileInputStream(file);
        fout = new FileOutputStream("file.txt");
        int byte_read;
        byte[] buffer = new byte[4096]; //4m
        byte_read = fin.read(buffer);
    while((byte_read = (fin.read(buffer))) != -1){
        fout.write(buffer, 0, byte_read);
    }
    }
    catch (...) {
        ...
    }
    finally {
          ...
    }

Thanks for reading!

EDIT: For those curious, here's the code I used to solve the aforementioned problem:

String stringToInsert = "insertSTringHERE";
byte[] answerByteArray = stringToInsert.getBytes();
ByteBuffer byteBuffer = ByteBuffer.wrap(answerByteArray);
Random rnum = new Random();
randChar = rnum.nextInt(4194002); //4MB worth of bytes

File fi = new File("file.txt");

RandomAccessFile raf = null;
try {
    raf = new RandomAccessFile(fi, "rw");
} catch (FileNotFoundException e1) {
    // TODO error handling and logging
}

FileChannel fo = null;
fo = raf.getChannel();

// Move to the beginning of the file and write out the contents
// of the byteBuffer.
try {
    outputFileChannel.position(randChar);
    while(byteBuffer.hasRemaining()) {
        fo.write(byteBuffer);
}
} catch (IOException e) {
    // TODO error handling and logging
}
try {
    outputFileChannel.close();
} catch (IOException e) {
    // TODO error handling and logging
}
try {
    randomAccessFile.close();
} catch (IOException e) {
    // TODO error handling and logging
}
bigbitecode
  • 253
  • 5
  • 16

2 Answers2

1

You probably want to use Java's random-access file features. Sun/Oracle has a Random Access Files tutorial that will probably be useful to you.

If you can't use Java 7, then look at RandomAccessFile which also has seek functionality and has existed since Java 1.0.

QuantumMechanic
  • 13,795
  • 4
  • 45
  • 66
-1

First off, for your files you could have the Files as global variables. This would all you to use the file when ever you needed without reading it again. Also note that if you keep making new files then you will lose the data that you have already acquired.

For example:

public class Foo {

  // Gloabal Vars //
  File file;

  public Foo(String location) {
     // Do Something
    file = new File(location);
  }

  public add() {
    // Add
  }

}

Answering your question, I would first read both files and then make all the changes you want in memory. After you have made all the changes, I would then write the changes to the file.

However, if the files are very large, then I would make all the changes one by one on the disk... it will be slower, but you will not run out of memory this way. For what you are doing I doubt you could use a buffer to help counter how slow it would be.

My overall suggestion would be to use arrays. For example I would do the following...

public char[] addCharsToString(String str, char[] newChars, int index) {
        char[] string = str.toCharArray();
        char[] tmp = new char[string.length + newChars.length];
        System.arraycopy(string, 0, tmp, 0, index);
        System.arraycopy(newChars, index, tmp, index, newChars.length);
        System.arraycopy(string, index + newChars.length, tmp, index + newChars.length, tmp.length - (newChars.length + index));
        return tmp;
}

Hope this helps!

Zeveso
  • 1,274
  • 3
  • 21
  • 41