I need to write to a file at a particular index position. BufferedWriter and PrintWriter does not allow writing to an index. How do I go about achieving this?
Basically what i want to do is if a file contains an empty line at the EOF then i need to write at that position, else insert a new line and write. Copying the contents of the file to a temporary file and then deleting the original file and then again renaming the temporary file to the original file's name isn't an option.
Thanks
You need to use a RandomAccessFile.
Using this class, you can go to a specific location using the seek(long) method and write using the different write methods.
In the case of your particuliar problem, the best solution weems to be
to use a RandomAccessFile and navigate to the end of your file. Check if this is a new line, write, close.
Given is the method to write content at particular position.
Lets say my file is Test.txt and content is as follow
Hello
How are you
Today is Monday
now you want to write "hi" after hello. So the offset for "hi" will be "5".
Method is :
filename = "test.txt";
offset = 5;
byte[] content = ("\t hi").getBytes();
private void insert(String filename, long offset, byte[] content) throws IOException {
RandomAccessFile r = new RandomAccessFile(filename, "rw");
RandomAccessFile rtemp = new RandomAccessFile(filename+"Temp", "rw");
long fileSize = r.length();
FileChannel sourceChannel = r.getChannel();
FileChannel targetChannel = rtemp.getChannel();
sourceChannel.transferTo(offset, (fileSize - offset), targetChannel);
sourceChannel.truncate(offset);
r.seek(offset);
r.write(content);
long newOffset = r.getFilePointer();
targetChannel.position(0L);
sourceChannel.transferFrom(targetChannel, newOffset, (fileSize - offset));
sourceChannel.close();
targetChannel.close();
rtemp.close();
r.close();
}
The output will be:
Hello hi
How are you
Today is Monday
Related
Hey I'm trying to open a file and read just from an offset for a certain length!
I read this topic:
How to read a specific line using the specific line number from a file in Java?
in there it said that it's not to possible read a certain line without reading the lines before, but I'm wondering about bytes!
FileReader location = new FileReader(file);
BufferedReader inputFile = new BufferedReader(location);
// Read from bytes 1000 to 2000
// Something like this
inputFile.read(1000,2000);
Is it possible to read certain bytes from a known offset?
RandomAccessFile exposes a function:
seek(long pos)
Sets the file-pointer offset, measured from the beginning of this file, at which the next read or write occurs.
FileInputStream.getChannel().position(123)
This is another possibility in addition to RandomAccessFile:
File f = File.createTempFile("aaa", null);
byte[] out = new byte[]{0, 1, 2};
FileOutputStream o = new FileOutputStream(f);
o.write(out);
o.close();
FileInputStream i = new FileInputStream(f);
i.getChannel().position(1);
assert i.read() == out[1];
i.close();
f.delete();
This should be OK since the docs for FileInputStream#getChannel say that:
Changing the channel's position, either explicitly or by reading, will change this stream's file position.
I don't know how this method compares to RandomAccessFile however.
This question already has answers here:
inserting data in the middle of a text file through java
(2 answers)
Closed 9 years ago.
Suppose i have a text file named Sample.text.
i need advice on how to achieve this:
Sample.txt before running a program:
ABCD
while running the program, user will input string to be added starting at the middle
for example: user input is XXX
Sample.txt after running a program:
ABXXXCD
Basically you've got to rewrite the file, at least from the middle. This isn't a matter of Java - it's a matter of what file systems support.
Typically the way to do this is to open both the input file and an output file, then:
Copy the first part from the input file to the output file
Write the middle section to the output file
Copy the remainder of the input file to the output file
Optionally perform file renaming if you want the new file to have the same eventual name as the original file
The basic idea is to read the file contents into memory, say at program start, manipulate the string as desired, then write the entire thing back to the file.
So you would open and read in Sample.txt. In memory you have a string = "ABCD"
in your program execution, accept user input of XXX. Insert that into your string with your favorite string manipulation method. Now string = "ABXXXCD"
Finally you would overwrite Sample.txt with your updated string and close it.
If you were worried about corruption or something, you might save it to a secondary file, then verify its contents, delete the original, and rename the new to be the same as the original.
Actually i have did something like what you want, here try this code, its not a complete but it should give you a clear idea:
public void addString(String fileContent, String insertData) throws IOException {
String firstPart = getFirstPart(fileContent);
Pattern p = Pattern.compile(firstPart);
Matcher matcher = p.matcher(fileContent);
int end = 0;
boolean matched = matcher.find();
if (matched) {
end = matcher.end();
}
if(matched) {
String secondPart = fileContent.substring(end);
StringBuilder newFileContent = new StringBuilder();
newFileContent.append(firstPart);
newFileContent.append(insertData);
newFileContent.append(secondPart);
writeNewFileContent(newFileContent.toString());
}
}
Normally a new file would be created, but the following probably suffices (for non-gigabyte files). Mind the explicit encoding UTF-8; which you can ommit for the encoding of the operating system.
public static void insertInMidstOfFile(File file, String textToInsert)
throws IOException {
if (!file.exists()) {
throw new FileNotFoundException("File not found: " + file.getPath());
// Because file open mode "rw" would create it.
}
if (textToInsert.isEmpty()) {
return;
}
long fileLength = file.length();
long startPosition = fileLength / 2;
long remainingLength = fileLength - startPosition;
if (remainingLength > Integer.MAX_VALUE) {
throw new IllegalStateException("File too large");
}
byte[] bytesToInsert = textToInsert.getBytes(StandardCharsets.UTF_8);
try (RandomAccessFile fh = new RandomAccessFile(file, "rw")) {
fh.seek(startPosition);
byte[] remainder = new byte[(int)remainingLength];
fh.readFully(remainder);
fh.seek(startPosition);
fh.write(bytesToInsert);
fh.write(remainder);
}
}
Java 7 or higher.
I wish to write data to a file at different offsets. Example, at 0th position, at (size/2)th position, at (size/4)th position etc. size represent the file size of the file meant to be created. Is this possible without creating different file parts and joining them?
Well you can write to anywhere you like in a file using RandomAccessFile - just use seek to get to the right place, and start writing.
However, this won't insert bytes at those places - it will just overwrite them (or add data at the end if you're writing past the end of the current file length, of course). It's not clear whether that's what you want or not.
What you are looking for are Random access files. From the official sun java tutorial site -
Random access files permit nonsequential, or random, access to a
file's contents. To access a file randomly, you open the file, seek a
particular location, and read from or write to that file.
This functionality is possible with the SeekableByteChannel interface.
The SeekableByteChannel interface extends channel I/O with the notion
of a current position. Methods enable you to set or query the
position, and you can then read the data from, or write the data to,
that location. The API consists of a few, easy to use, methods:
position – Returns the channel's current position
position(long) – Sets the channel's position
read(ByteBuffer) – Reads bytes into the buffer from the channel
write(ByteBuffer) – Writes bytes from the buffer to the channel
truncate(long) – Truncates the file (or other entity) connected to the channel
and an example, which is provided there -
String s = "I was here!\n";
byte data[] = s.getBytes();
ByteBuffer out = ByteBuffer.wrap(data);
ByteBuffer copy = ByteBuffer.allocate(12);
try (FileChannel fc = (FileChannel.open(file, READ, WRITE))) {
// Read the first 12
// bytes of the file.
int nread;
do {
nread = fc.read(copy);
} while (nread != -1 && copy.hasRemaining());
// Write "I was here!" at the beginning of the file.
// See how they are moving back to the beginning of the
// file?
fc.position(0);
while (out.hasRemaining())
fc.write(out);
out.rewind();
// Move to the end of the file. Copy the first 12 bytes to
// the end of the file. Then write "I was here!" again.
long length = fc.size();
// Now see here. They are going to the end of the file.
fc.position(length-1);
copy.flip();
while (copy.hasRemaining())
fc.write(copy);
while (out.hasRemaining())
fc.write(out);
} catch (IOException x) {
System.out.println("I/O Exception: " + x);
}
If this isn't a huge file you can read the entire thing and than edit the array:
public String read(String fileName){
BufferedReader br = new BufferedReader(new FileReader(fileName));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
String everything = sb.toString();
} finally {
br.close();
}
}
public String edit(String fileContent, Byte b, int offset){
Byte[] bytes = fileContent.getBytes();
bytes[offset] = b;
return new String(bytes);
]
and then write it back to the file (or just delete the old one and write the byte array to a new file with the same name)
I have a binary file which contains image.i have to jump on different locations in file to read the image file. So far i am using mark and reset methods but these are not helping me as i want.
please somebody help me about that i,ll be really thankful.and i am using Input Stream to read the file.
You can use the java.io.RandomAccessFile to do this. The methods seek(long) and getFilePointer() will help to jump to different offsets in the file and come back to original offsets:
RandomAccessFile f = new RandomAccessFile("/my/image/file", "rw");
// read some data.
long positionToJump = 10L;
long origPos = f.getFilePointer(); // store the original position
f.seek(positionToJump);
// now you are at position 10, start reading from here.
// go back to original position
f.seek(origPos);
Android seems to have RandomAccessFile, have you tried it?
Since Java 7 you can use java.nio.file.Files and SeekableByteChannel
byte[] getRandomAccessResults(Path filePath, long offset) throws IOException
{
try (SeekableByteChannel byte_channel = java.nio.file.Files.newByteChannel(filePath, StandardOpenOption.READ))
{
ByteBuffer byte_buffer = ByteBuffer.allocate(128);
byte_channel.position(offset);
byte_channel.read(byte_buffer);
return byte_buffer.array();
}
}
I would like to create a simple program (in Java) which edits text files - particularly one which performs inserting arbitrary pieces of text at random positions in a text file. This feature is part of a larger program I am currently writing.
Reading the description about java.util.RandomAccessFile, it appears that any write operations performed in the middle of a file would actually overwrite the exiting content. This is a side-effect which I would like to avoid (if possible).
Is there a simple way to achieve this?
Thanks in advance.
Okay, this question is pretty old, but FileChannels exist since Java 1.4 and I don't know why they aren't mentioned anywhere when dealing with the problem of replacing or inserting content in files. FileChannels are fast, use them.
Here's an example (ignoring exceptions and some other stuff):
public void insert(String filename, long offset, byte[] content) {
RandomAccessFile r = new RandomAccessFile(new File(filename), "rw");
RandomAccessFile rtemp = new RandomAccessFile(new File(filename + "~"), "rw");
long fileSize = r.length();
FileChannel sourceChannel = r.getChannel();
FileChannel targetChannel = rtemp.getChannel();
sourceChannel.transferTo(offset, (fileSize - offset), targetChannel);
sourceChannel.truncate(offset);
r.seek(offset);
r.write(content);
long newOffset = r.getFilePointer();
targetChannel.position(0L);
sourceChannel.transferFrom(targetChannel, newOffset, (fileSize - offset));
sourceChannel.close();
targetChannel.close();
}
Well, no, I don't believe there is a way to avoid overwriting existing content with a single, standard Java IO API call.
If the files are not too large, just read the entire file into an ArrayList (an entry per line) and either rewrite entries or insert new entries for new lines.
Then overwrite the existing file with new content, or move the existing file to a backup and write a new file.
Depending on how sophisticated the edits need to be, your data structure may need to change.
Another method would be to read characters from the existing file while writing to the edited file and edit the stream as it is read.
If Java has a way to memory map files, then what you can do is extend the file to its new length, map the file, memmove all the bytes down to the end to make a hole and write the new data into the hole.
This works in C. Never tried it in Java.
Another way I just thought of to do the same but with random file access.
Seek to the end - 1 MB
Read 1 MB
Write that to original position + gap size.
Repeat for each previous 1 MB working toward the beginning of the file.
Stop when you reach the desired gap position.
Use a larger buffer size for faster performance.
You can use following code:
BufferedReader reader = null;
BufferedWriter writer = null;
ArrayList list = new ArrayList();
try {
reader = new BufferedReader(new FileReader(fileName));
String tmp;
while ((tmp = reader.readLine()) != null)
list.add(tmp);
OUtil.closeReader(reader);
list.add(0, "Start Text");
list.add("End Text");
writer = new BufferedWriter(new FileWriter(fileName));
for (int i = 0; i < list.size(); i++)
writer.write(list.get(i) + "\r\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
OUtil.closeReader(reader);
OUtil.closeWriter(writer);
}
I don't know if there's a handy way to do it straight otherwise than
read the beginning of the file and write it to target
write your new text to target
read the rest of the file and write it to target.
About the target : You can construct the new contents of the file in memory and then overwrite the old content of the file if the files handled aren't so big. Or you can write the result to a temporary file.
The thing would probably be easiest to do with streams, RandomAccessFile doesn't seem to be meant for inserting in the middle (afaik). Check the tutorial if you need.
I believe the only way to insert text into an existing text file is to read the original file and write the content in a temporary file with the new text inserted. Then erase the original file and rename the temporary file to the original name.
This example is focused on inserted a single line into an existing file, but still maybe of use to you.
If it is a text file,,,,Read the existing file in StringBuffer and append the new content in the same StringBuffer now u can write the SrtingBuffer on file. so now the file contains both the existing and new text.
As #xor_eq answer's edit queue is full, here in a new answer a more documented and slightly improved version of his:
public static void insert(String filename, long offset, byte[] content) throws IOException {
File temp = Files.createTempFile("insertTempFile", ".temp").toFile(); // Create a temporary file to save content to
try (RandomAccessFile r = new RandomAccessFile(new File(filename), "rw"); // Open file for read & write
RandomAccessFile rtemp = new RandomAccessFile(temp, "rw"); // Open temporary file for read & write
FileChannel sourceChannel = r.getChannel(); // Channel of file
FileChannel targetChannel = rtemp.getChannel()) { // Channel of temporary file
long fileSize = r.length();
sourceChannel.transferTo(offset, (fileSize - offset), targetChannel); // Copy content after insert index to
// temporary file
sourceChannel.truncate(offset); // Remove content past insert index from file
r.seek(offset); // Goto back of file (now insert index)
r.write(content); // Write new content
long newOffset = r.getFilePointer(); // The current offset
targetChannel.position(0L); // Goto start of temporary file
sourceChannel.transferFrom(targetChannel, newOffset, (fileSize - offset)); // Copy all content of temporary
// to end of file
}
Files.delete(temp.toPath()); // Delete the temporary file as not needed anymore
}