I developed a java program which is writing data into a file(temporary file) using asynchronousFileChannel.
Now each time it writes a entry to the file a second method will be called which will check for its size and if its size exceeds a pre thresold size say 10000 bytes,all the file contents should be moved to a different file(permanent Datarecord).
What should i use so that no data should be lost while moving data from temp file to permanent file while the temporary file is still been accessed by different threads.
4 回答
10,000 bytes is not very much, it is just <10kb. So I think you can buffer all this data in queue and when size exceeds you can clear(delete-create) temporary file and flush queue data to permanent storage file.
Since you are using AsynchronousFileChannel, there is always a problem that when one of your methods is trying to move the file, another thread might be trying to read/write to it.
You need to do the move by other means.
If what you are doing is logging, which I think you might be doing - use a FileHandler to roll the file. See an example here - http://kodejava.org/how-do-i-create-a-rolling-log-files/
You can also see some discussion about rolling files here - Rolling file implementation
Another one on stackoverflow - Rolling logs by both size and time
And another one - How to write statistical data into rolling files in java
Hope this helps. Good Luck.
Just close the file, rename it, and open a new one. You're overthinking this.
Here's the code I wrote for you...
public class RollMyFile {
private long FILE_MAX_SIZE;
private String fileName;
/**
* Constructor to take in the initial file name and the maxFileSize
* @param fileNameToStartWith
*/
public RollMyFile(String fileNameToStartWith, long maxFileSize) {
this.fileName = fileNameToStartWith;
this.FILE_MAX_SIZE = maxFileSize;
}
/**
* Synchronized to roll over to a new file
*
* @param fileChannel
* @return
* @throws IOException
*/
public synchronized AsynchronousFileChannel rollMeIfNeeded(AsynchronousFileChannel fileChannel) throws IOException {
if(fileChannel.size()>FILE_MAX_SIZE) {
this.fileName = getNewRolledFileName(this.fileName);
File file = new File(this.fileName);
file.createNewFile();
fileChannel = getAsyncChannel(this.fileName);
}
return fileChannel;
}
/**
* Change this to create a new name for the roll over file
* @param currentFileName
* @return
*/
public String getNewRolledFileName(String currentFileName) {
if (currentFileName.contains(".")) {
currentFileName = currentFileName.substring(0,
currentFileName.lastIndexOf('.'));
}
return currentFileName+ "." + Calendar.getInstance().getTimeInMillis();
}
/**
* This is where you request to write a whole bunch of stuff that
* you said you want to store
*
* @param stuffToWrite
* @throws IOException
*/
public void write(StringBuffer stuffToWrite) throws IOException {
AsynchronousFileChannel fileChannel = getAsyncChannel(this.fileName);
fileChannel = rollMeIfNeeded(fileChannel);
ByteBuffer byteBuffer = ByteBuffer.wrap(stuffToWrite.toString().getBytes());
fileChannel.write(byteBuffer, fileChannel.size());
}
/**
* Change this to how ever you 'open' the AsynchronousFileChannel
*
* @param givenFileName
* @return
* @throws IOException
*/
private AsynchronousFileChannel getAsyncChannel(String givenFileName) throws IOException {
return AsynchronousFileChannel.open(Paths.get(givenFileName), StandardOpenOption.WRITE);
}
}
And I used it like below
public class Tester {
public static void main(String[] args) {
RollMyFile rmf = new RollMyFile("my-current-file", 1000);
try {
for(int i=1; i<1000; i++) {
rmf.write(new StringBuffer(" lots of important stuff to store... "));
System.out.println(i);
}
System.out.println("end");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}