I am reading a file using RandomFileAccess, FileChannel and ByteBuffer as follows:
RandomAccessFile myFile = new RandomAccessFile("/Users/****/Documents/a.txt", "rw");
FileChannel myInChannel = myFile.getChannel();
ByteBuffer bb = ByteBuffer.allocate(48);
int bytesRead = myInChannel.read(bb);
while (bytesRead != -1) {
// do something
}
myFile.close();
All this code is working fine.
But i am wondering is there any way i can read the data using Future?
I tried following code, and it worked fine for:
try(AsynchronousFileChannel afileChannel = AsynchronousFileChannel.open(Paths.get("/Users/***/Documents/myFile.txt"), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
long position = 0;
Future<Integer> operation = afileChannel.read(buffer, position);
while(!operation.isDone()){
//do something
}
buffer.flip();
byte[] data = new byte[buffer.limit()];
buffer.get(data);
System.out.println(new String(data));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Got to know that this can be done via AsynchronousFileChannel but not via FileChannel.
Related
Java 8
Here classic try-catch block.
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
byte[] bytes = new byte[1024];
int read = 0;
int totalRead = 0;
while ((read = iStream.read(bytes)) > 0) {
// some code here
}
return totalRead;
} catch (Exception e) {
throw new IOException(fileName + " failed, got: " + e.toString(), e);
} finally {
if (out != null) {
out.getFD().sync();
out.close();
}
}
As you can see I do some custom logic in the finally block
out.getFD().sync();
Nice. It's work fine.
Now I want to replace it by try-with-resources block. I try this
try (FileOutputStream out = new FileOutputStream(file)) {
byte[] bytes = new byte[1024];
int read = 0;
int totalRead = 0;
while ((read = iStream.read(bytes)) > 0) {
// som ecode here
}
return totalRead;
} catch (Exception e) {
throw new IOException(fileName + " failed, got: " + e.toString(), e);
} finally {
if (out != null) {
out.getFD().sync();
out.close();
}
}
but get compile error in finally block:
cannot find symbol
symbol: variable out
The whole point of try-with-resources is that you do not need to call close() as the compiler ensures that it has been called. Since this happens before the finally block is executed, you can’t perform other actions on the resource in finally, like the sync call.
You can easily verify this
try(Closeable c = () -> System.out.println("close")) {
throw new IOException("stop here");
}
finally {
System.out.println("In finally block");
}
will print
close
In finally block
Exception in thread "main" java.io.IOException: stop here
If you really need to perform a sync operation at the end (in most cases: you don’t), you still don’t have to do it manually
try(OutputStream out = Files.newOutputStream(file.toPath(), StandardOpenOption.SYNC,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
byte[] bytes = new byte[1024];
int read = 0;
int totalRead = 0;
while ((read = iStream.read(bytes)) > 0) {
// some code here
}
return totalRead;
}
I hope, your “some code” is not just a plain copying which you could simply do with Files.copy(Path, Path, …) or Files.copy(InputStream, Path, …).
You should also consider using long for totalRead…
This question already has an answer here:
Using PdfBox, how do I retrieve contents of PDDocument as a byte array?
(1 answer)
Closed 5 years ago.
Using spring and pdfbox apache library I have edited the PDF in controller, but nor sure how I can save this pdf to classpath so that I can convert the saved pdf to bytes and pass it on to a service.
Any help is appreciated. Thank you.
My controller code below:
#RequestMapping("/individual/load/editablePDF.do")
public void getFile(HttpServletRequest request,HttpServletResponse response) throws IOException {
Resource resource = new ClassPathResource("EditableFile.pdf");
InputStream resourceInputStream = resource.getInputStream();
PDDocument pdfDoc = PDDocument.load(resourceInputStream);
PDDocumentCatalog docCatalog = pdfDoc.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
List<PDField> fieldList = acroForm.getFields();
String[] fieldArray = new String[fieldList.size()];
int i = 0;
for (PDField sField : fieldList) {
fieldArray[i] = sField.getFullyQualifiedName();
i++;
}
for (String f : fieldArray) {
PDField field = acroForm.getField(f);
System.out.println("f is: " + f);
if (f.contains("company name")) {
String value = "Discovery";
field.setValue(value);
System.out.println("printed: " + value + " to: " + f);
}
}
try {
pdfDoc.save("D:\\workspace\\TestSamples\\src\\Editable_ Discovery wellness days application form 2017-SAVED.pdf");//Not sure how to achieve this?
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pdfDoc.close();
}
This worked for me.
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
document.save(byteArrayOutputStream);
document.close();
InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
In my spring-batch-integration app, file polling invokes the batchjob for eachfile and this application could be running on multiple servers(nodes) but they all are supposed to read a common directory.Now, I wrote a custom locker which takes the lock on file so that any other instance will not be able to process the same file . code as below
public class MyFileLocker extends AbstractFileLockerFilter{
private final ConcurrentMap<File, FileLock> lockCache = new ConcurrentHashMap<File, FileLock>();
private final ConcurrentMap<File, FileChannel> ChannelCache = new ConcurrentHashMap<File, FileChannel>();
#Override
public boolean lock(File fileToLock) {
FileChannel channel;
FileLock lock;
try {
channel = new RandomAccessFile(fileToLock, "rw").getChannel();
lock = channel.tryLock();
if (lock == null || !lock.isValid()) {
System.out.println(" Problem in acquiring lock!!" + fileToLock);
return false;
}
lockCache.put(fileToLock, lock);
ChannelCache.put(fileToLock, channel);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
#Override
public boolean isLockable(File file) {
return file.canWrite();
}
#Override
public void unlock(File fileToUnlock) {
FileLock lock = lockCache.get(fileToUnlock);
try {
if(lock!=null){
lock.release();
ChannelCache.get(fileToUnlock).close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now, when i invoke my Spring batch and i try to read that file using flatfileitemreader it gives me
org.springframework.batch.item.file.NonTransientFlatFileException
which i believe is coming beacuse file is locked. I did some googling and found that NIOLocker locks the file in a way that even the current thread can't read it. I found a link where it shows how to read the locked file but they are using buffer.
How can I make my file accessible to my FlatfileItemReader.
Please suggest.
Yes, you really can get access to the locked file content only over ByteBuffer:
FileChannel fileChannel = channelCache.get(lockedFile);
ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileChannel.size());
fileChannel.read(byteBuffer);
System.out.println("Read File " + lockedFile.getName() + " with content: " + new String(byteBuffer.array()));
Oh! Yeah. You really pointed to my repo :-).
So, with locker you don't have choice unless copy/paste the file byte[] that way before FlatfileItemReader or just inject some custom BufferedReaderFactory into the same FlatfileItemReader, which converts the locked file to the appropriate BufferedReader:
new BufferedReader(new CharArrayReader(byteBuffer.asCharBuffer().array()));
Based on the link that you shared, looks like you could try the following.
//This is from your link (except the size variable)
FileChannel fileChannel = channelCache.get(lockedFile);
int size = (int) fileChannel.size();
ByteBuffer byteBuffer = ByteBuffer.allocate(size);
fileChannel.read(byteBuffer);
//Additional code that you could try
byte[] bArray = new byte[size];
//Write data to the byte array
byteBuffer.get(bArray);
FlatFileItemReader flatFileItemReader = new FlatFileItemReader();
flatFileItemReader.setResource(new ByteArrayResource(bArray));
//Next you can try reading from your flatFileItemReader as usual
...
Let me know if it doesn't progress your issue.
Solution : I am creating a temporary file with content of the locked file and processing it. Once processing is done i archive that file and remove the locked and temporary both files. Key here is to create a new file with locked file content. code for below is as follows :
File tmpFile = new File(inputFile.getAbsolutePath() + ".lck");
FileChannel fileChannel = MyFileLocker.getChannelCache().get(new File(inputFile.getAbsolutePath()));
InputStream inputStream = Channels.newInputStream(fileChannel);
ByteStreams.copy(inputStream, Files.newOutputStreamSupplier(tmpFile));
Here inputFile is my locked file and tmp file is new file with locked file content. I have also created a method in my locker class to unlock and delete
public void unlockAndDelete(File fileToUnlockandDelete) {
FileLock lock = lockCache.get(fileToUnlockandDelete);
String fileName = fileToUnlockandDelete.getName();
try {
if(lock!=null){
lock.release();
channelCache.get(fileToUnlockandDelete).close();
//remove from cache
lockCache.remove(fileToUnlockandDelete);
channelCache.remove(fileToUnlockandDelete);
boolean isFiledeleted = fileToUnlockandDelete.delete();
if(isFiledeleted){
System.out.println("File deleted successfully" + fileName);
}else{
System.out.println("File is not deleted."+fileName);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I am having problems getting an image back from the default android gallery. All I want to do is call the Android standard gallery intent and return the uri for the image in my onActivityResult. When I run this code it open the gallery just fine but then it force closes whenever I click on a picture. Any tips for this would be helpful.
private void doGallery() {
Intent galleryIntent = new Intent();
galleryIntent.setType(IJudgeSingleton.IMAGEINTENT);
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(galleryIntent, "Select Picture"), IJudgeSingleton.REQUEST_CODE_GALLERY);
}
case IJudgeSingleton.REQUEST_CODE_GALLERY:
Uri uri = data.getData();
mSingleton.mFileTemp = new File(getMediaPath(uri));
try {
IJudgeSingleton.copy(mSingleton.mFileTemp, mSingleton.mCropFileTemp);
mData.setImageSet(true, mSingleton.mFileTemp.toURI().toString(), true);
mData.setPhoto(true);
}
catch (IOException e) {
Log.d(this.getClass().getName(), "REQUEST_CODE_GALLERY", e);
}
break;
Figured it out my file was pointing to a null so that's what was giving me the force close. Also I had to add change some code around in my onActivityResult for REQUEST_CODE_GALLERY. I have posted the added code below for anyone who has this problem.
case IJudgeSingleton.REQUEST_CODE_GALLERY:
Uri uri = data.getData();
//This takes the uri/image returned from the gallery intent a places it into a file.
final int chunkSize = 1024; // We'll read in one kB at a time
byte[] imageData = new byte[chunkSize];
try {
InputStream in = getContentResolver().openInputStream(uri);
OutputStream out = new FileOutputStream(mSingleton.mFileTemp); // I'm assuming you already have the File object for where you're writing to
int bytesRead;
while ((bytesRead = in.read(imageData)) > 0) {
out.write(Arrays.copyOfRange(imageData, 0, Math.max(0, bytesRead)));
}
in.close();
out.close();
} catch (Exception ex) {
Log.e(this.getClass().getName(),"REQUEST_CODE_GALLERY");
}
// mSingleton.mFileTemp = new File(getMediaPath(uri));
try {
IJudgeSingleton.copy(mSingleton.mFileTemp, mSingleton.mCropFileTemp);
mData.setImageSet(true, mSingleton.mFileTemp.toURI().toString(), true);
mData.setPhoto(true);
}
catch (IOException e) {
Log.d(this.getClass().getName(), "REQUEST_CODE_GALLERY", e);
}
break;
case IJudgeSingleton.REQUEST_CODE_DEFAULT_CAPTURE:
mData = data.getParcelableExtra(IJudgeSingleton.SURVEY_INTENT);
showListView();
completedIntent = false;
I have researched and tried to refer back to my fileChooser.getSeletedFile() in my save as action but can not work out how to check whether or not a file has been created. Here is my attempted code so far:
Save as code(works well):
public void Save_As() {
fileChooserTest.setApproveButtonText("Save");
int actionDialog = fileChooserTest.showOpenDialog(this);
File fileName = new File(fileChooserTest.getSelectedFile() + ".txt");
try {
if (fileName == null) {
return;
}
BufferedWriter outFile = new BufferedWriter(new FileWriter(fileName));
outFile.write(this.jTextArea2.getText());//put in textfile
outFile.flush(); // redundant, done by close()
outFile.close();
} catch (IOException ex) {
}
}
"Save" code doesn't work:
private void SaveActionPerformed(java.awt.event.ActionEvent evt) {
File f = fileChooserTest.getSelectedFile();
try {
if (f.exists()) {
BufferedWriter bw1 = new BufferedWriter(new FileWriter(fileChooserTest.getSelectedFile() + ".txt"));
bw1 = new BufferedWriter(new FileWriter(fileChooserTest.getSelectedFile() + ".txt"));
String text = ((JTextArea) jTabbedPane1.getSelectedComponent()).getText();
bw1.write(text);
bw1.close();
} else {
Save_As();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
Instead of storing an instance to the JFileChooser rather store an instance to the File (wich will be null before any save has been performed). In your SaveActionPerformed method check if the file is null. If it is null then do a Save_As and store the selected file in your file variable, if it is not null then do a normal save into the file.