Access the same file for read and write random position - java

Start by saying that I have not great experience in Java and I've done a lot of research. I would please ask you a specific question.
Thank you
I need to open a file for reading and writing from which I read and write a 512-byte blocks.
The file is fixed length and the information to be written will overlap with other existing.
For example, I read the first 512 bytes of the file and if it contains certain values write a block 512 to position 2048.
I tried using FileInputStream and FileOutputStream but every time I open with FileOutputStream the contents of the file are deleted.
It can be done with Java?
Roberto

Use a FileChannel; it allows random access to any part of a file, in read, write or any combination of both.
Example:
final Path path = Paths.get("path/to/the/file");
final FileChannel channel = FileChannel.open(path, relevantOptions);
Optionally, after that, you can use the .map() method.

Related

Getting a wrong FileChannel size

I'm trying to get the size of a file contained in assets.
I'm using a FileChannel because I need a FileChannel later.
The file myfile.txt contains 7 bytes.
Here is my code:
AssetManager amgr;
AssetFileDescriptor afd;
FileChannel fchIn;
FileInputStream fis;
amgr=context.getAssets();
afd=amgr.openFd("myfile.txt");
fis=afd.createInputStream();
fchIn=fis.getChannel();
Log.d("mytag", fchIn.size());
Log.d("mytag", fis.available());
And the output is:
7237492
7
Why is the size returned by the FileChannel.size() method wrong ?
Thanks for your help
FileInputStream.getChannel() documentation says it "Returns a read-only FileChannel that shares its position with this stream." You are assuming that the channel begins and ends exactly at the boundaries of your file, which is the only way its total size() would match what you expect, but the documentation does not make that guarantee.
Also note that FileInputStream.available() is not documented to mean the same thing as total size -- technically, it is the amount of data available to read without needing to load/buffer more from the source. Unless the entire source has already been read into memory, it may have almost nothing to do with the actual file size.
I expect that the underlying FileChannel has access to a large range of bytes for multiple files, like all of your assets combined (and hence the large size), and you'd need to reference the AssetFileDescriptor's getStartOffset() and getLength() methods to know the actual position of the associated file's bytes within the channel. My guess is that AssetFileDescriptor.createInputStream() is giving you an object that already knows the position and range and takes care of that for you. If you're going to use the raw channel, then honor the information in the file descriptor. Also note that, per the documentation, if you move the position of the FileInputStream (e.g. by reading bytes) then you also move the position of the channel at the same time, so be careful if you're trying to use both.

Java: Replace part of file without writing the entire file again

Is it possible to replace part of a files content, without rewriting the entire file to the disk.
Say that i have a very large file of several gigabytes, how to i replace the bytes from, lets say position 100 to 200 without rewriting the entire file?
As an added bonus, i need a solution that does not use any features never than java 1.4.
If you're positive that you're going to be writing exactly the same number of bytes, you can use a RandomAccessFile to accomplish this (available since Java 1.0). Just open the file, seek to wherever you need to be, and overwrite those bytes with whatever your new data is.
RandomAccessFile f = new RandomAccessFile(new File("C:\\test\\huge.txt"), "rw");
f.seek(100); // Seek ahead
f.write("here is some new stuff".getBytes())
You can also read from the file at arbitrary points in the same fashion, in case you don't know exactly how much data you need to replace (e.g. so you can pad/truncate whatever you're writing to avoid doing something awful by accident).

Java 6 File Input Output Stream (same file)

I searched and looked at multiple questions like this, but my question is really different than anything I found. I've looked at Java Docs.
How do I get the equivalent of this c file open:
stream1 = fopen (out_file, "r+b");
Once I've done a partial read from the file, the first write makes the next read return EOF no matter how many bytes were in the file.
Essentially I want a file I/O stream that doesn't do that. The whole purpose of what I'm trying to do is to replace the bytes in an existing file in the current file. I don't want to do it in a copy or make a copy before I do the Read->Write.
You can use a RandomAccessFile.
As Perception mentions, you can use a RandomAccessFile. Also, in some situations, a FileChannel may work better. I've used these to handle binary file data with great success.
EDIT: you can get a FileChannel from the RandomAccessFile object using getChannel.

How do I write/read to the beginning of a text file?

EDIT
This is my file reader, can I make this read it from bottom to up seeing how difficult it is to make it write from bottom to up.
BufferedReader mainChat = new BufferedReader(new FileReader("./messages/messages.txt"));
String str;
while ((str = mainChat.readLine()) != null)
{
System.out.println(str);
}
mainChat.close();
OR (old question)
How can I make it put the next String at the beginning of the file and then insert an new line(to shift the other lines down)?
FileWriter chatBuffer = new FileWriter("./messages/messages.txt",true);
BufferedWriter mainChat = new BufferedWriter(chatBuffer);
mainChat.write(message);
mainChat.newLine();
mainChat.flush();
mainChat.close();
Someone could correct me, but I'm pretty sure in most operating systems, there is no option but to read the whole file in, then write it back again.
I suppose the main reason is that, in most modern OSs, all files on the disc start at the beginning of a boundary. The problem is, you cannot tell the file allocation table that your file starts earlier than that point.
Therefore, all the later bytes in the file have to be rewritten. I don't know of any OS routines that do this in one step.
So, I would use a BufferedReader to store whole file into a Vector or StringBuffer, then write it all back with the prepended string first.
--
Edit
A way that would save memory for larger files, reading #Saury's randomaccessfile suggestion, would be:
file has N bytes to start with
we want to add on "hello world"
open the file for append
append 11 spaces
i=N
loop {
go back to byte i
read a byte
move to byte i+11
write that byte back
i--
} until i==0
then move to byte 0
write "hello world"
voila
Use FileUtils from Apache Common IO to simplify this if you can. However, it still needs to read the whole file in so it will be slow for large files.
List<String> newList = Arrays.asList("3");
File file = new File("./messages/messages.txt");
newList.addAll(FileUtils.readLines(file));
FileUtils.writeLines(file, newList);
FileUtils also have read/write methods that take care of encoding.
Use RandomAccessFile to read/write the file in reverse order. See following links for more details.
http://www.java2s.com/Code/Java/File-Input-Output/UseRandomAccessFiletoreverseafile.htm
http://download.oracle.com/javase/1.5.0/docs/api/java/io/RandomAccessFile.html
As was suggested here pre-pending to a file is rather difficult and is indeed linked to how files are stored on the hard drive. The operation is not naturally available from the OS so you will have to make it yourself and most obvious answers to this involve reading the whole file and writing it again. this may be fine for you but will incur important costs and could be a bottleneck for your application performance.
Appending would be the natural choice but this would, as far as I understand, make reading the file unnatural.
There are many ways you could tackle this depending on the specificities of your situation.
If writing this file is not time critical in your application and the file does not grow too big you could bite the bullet and read the whole file, prepend the information and write it again. apache's common-io's FileUtils will be of help here simpifying the operation where you can read the file as a list of strings, prepend the new lines to the list and write the list again.
If writing is time critical but have control over the reading or the file. That is, if the file is to be read by another of your programs. you could load the file in a list of lines and reverse the list. Again FileUtils from the common-io library and helper functions in the Collections class in the standard JDK should do the trick nicely.
If writing is time critical but the file is intended to be read through a normal text editor you could create a small class or program that would read the file and write it in another file with the preferred order.

Best Way to Write Bytes in the Middle of a File in Java

What is the best way to write bytes in the middle of a file using Java?
Reading and Writing in the middle of a file is as simple as using a RandomAccessFile in Java.
RandomAccessFile, despite its name, is more like an InputStream and OutputStream and less like a File. It allows you to read or seek through bytes in a file and then begin writing over whichever bytes you care to stop at.
Once you discover this class, it is very easy to use if you have a basic understanding of regular file i/o.
A small example:
public static void aMethod(){
RandomAccessFile f = new RandomAccessFile(new File("whereDidIPutTHatFile"), "rw");
long aPositionWhereIWantToGo = 99;
f.seek(aPositionWhereIWantToGo); // this basically reads n bytes in the file
f.write("Im in teh fil, writn bites".getBytes());
f.close();
}
Use RandomAccessFile
Tutorial
Javadocs
Open the file in write mode without truncating it, seek to the desired offset, and write the desired data. Just be careful about text/binary mode.
I think it’s best to create file chunks every time. And when the file is downloaded, connect them together. Now I'm working on it.

Categories

Resources