I am using a library that uses Java NIO in order to directly map files to memory, but I am having trouble reading disks directly.
I can read the disks directly using FileInputStream with UNC, such as
File disk = new File("\\\\.\\PhysicalDrive0\\");
try (FileInputStream fis = new FileInputStream(disk);
BufferedInputStream bis = new BufferedInputStream(fis)) {
byte[] somebytes = new byte[10];
bis.read(somebytes);
} catch (Exception ex) {
System.out.println("Oh bother");
}
However, I can't extend this to NIO:
File disk = new File("\\\\.\\PhysicalDrive0\\");
Path path = disk.toPath();
try (FileChannel fc = FileChannel.open(path, StandardOpenOption.READ)){
System.out.println("No exceptions! Yay!");
} catch (Exception ex) {
System.out.println("Oh bother");
}
The stacktrace (up to the cause) is:
java.nio.file.FileSystemException: \\.\PhysicalDrive0\: The parameter is incorrect.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.newFileChannel(WindowsFileSystemProvider.java:115)
at java.nio.channels.FileChannel.open(FileChannel.java:287)
at java.nio.channels.FileChannel.open(FileChannel.java:334)
at hdreader.HDReader.testcode(HDReader.java:147)
I haven't been able to find a solution, though I saw something close on How to access specific raw data on disk from java. The answer by Daniel Alder suggesting the use of GLOBALROOT seems to be relevant, as the answer uses FileChannel in the answer, but I can't seem to find the drive using this pattern. Is there a way to list all devices under GLOBALROOT or something like that?
At the moment I am looking at replacing uses of NIO with straight InputStreams, but I want to avoid this if I can. Firstly, NIO was used for a reason, and secondly, it runs through a lot of code and will require a lot of work. Finally, I'd like to know how to implement something like Daniel's solution so that I can write to devices or use NIO in the future.
So in summary: how can I access drives directly with Java NIO (not InputStreams), and/or is there a way to list all devices accessible through GLOBALROOT so that I might use Daniel Alser's solution?
Summary of Answers:
I have kept the past edits (below) to avoid confusion. With the help of EJP and Apangin I think I have a workable solution. Something like
private void rafMethod(long posn) {
ByteBuffer buffer = ByteBuffer.allocate(512);
buffer.rewind();
try (RandomAccessFile raf = new RandomAccessFile(disk.getPath(), "r");
SeekableByteChannel sbc = raf.getChannel()) {
sbc.read(buffer);
} catch (Exception ex) {
System.out.println("Oh bother: " + ex);
ex.printStackTrace();
}
return buffer;
}
This will work as long as the posn parameter is a multiple of the sector size (set at 512 in this case). Note that this also works with the Channels.newChannel(FileInputStream), which seems to always return a SeekableByteStream in this case and it appears it is safe to cast it to one.
From quick and dirty testing it appears that these methods truly do seek and don't just skip. I searched for a thousand locations at the start of my drive and it read them. I did the same but added an offset of half of the disk size (to search the back of the disk). I found:
Both methods took almost the same time.
Searching the start or the end of the disk did not affect time.
Reducing the range of the addresses did reduce time.
Sorting the addresses did reduce time, but not by much.
This suggests to me that this is truly seeking and not merely reading and skipping (as a stream tends to). The speed is still terrible at this stage and it makes my hard drive sound like a washing machine, but the code was designed for a quick test and has yet to be made pretty. It may still work fine.
Thanks to both EJP and Apangin for the help. Read more in their respective answers.
Edit:
I have since run my code on a Windows 7 machine (I didn't have one originally), and I get a slightly different exception (see below). This was run with admin privileges, and the first piece of code still works under the same conditions.
java.nio.file.FileSystemException: \\.\PhysicalDrive0\: A device attached to the system is not functioning.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.newFileChannel(WindowsFileSystemProvider.java:115)
at java.nio.channels.FileChannel.open(FileChannel.java:287)
at java.nio.channels.FileChannel.open(FileChannel.java:335)
at testapp.TestApp.doStuff(TestApp.java:30)
at testapp.TestApp.main(TestApp.java:24)
Edit 2:
In response to EJP, I have tried:
byte[] bytes = new byte[20];
ByteBuffer bb = ByteBuffer.wrap(bytes);
bb.rewind();
File disk = new File("\\\\.\\PhysicalDrive0\\");
try (FileInputStream fis = new FileInputStream(disk);
ReadableByteChannel rbc = Channels.newChannel(new FileInputStream(disk))) {
System.out.println("Channel created");
int read = rbc.read(bb);
System.out.println("Read " + read + " bytes");
System.out.println("No exceptions! Yay!");
} catch (Exception ex) {
System.out.println("Oh bother: " + ex);
}
When I try this I get the following output:
Channel created
Oh bother: java.io.IOException: The parameter is incorrect
So it appears that I can create a FileChannel or ReadableByteChannel, but I can't use it; that is, the error is simply deferred.
When accessing physical drive without buffering, you can read only complete sectors. This means, if a sector size is 512 bytes, you can read only multiple of 512 bytes. Change your buffer length to 512 or 4096 (whatever your sector size is) and FileChannel will work fine:
ByteBuffer buf = ByteBuffer.allocate(512);
try (RandomAccessFile raf = new RandomAccessFile("\\\\.\\PhysicalDrive0", "r");
FileChannel fc = raf.getChannel()) {
fc.read(buf);
System.out.println("It worked! Read bytes: " + buf.position());
} catch (Exception e) {
e.printStackTrace();
}
See Alignment and File Access Requirements.
Your original FileInputStream code works obviously because of BufferedInputStream which has the default buffer size of 8192. Take it away - and the code will fail with the same exception.
Using NIO your original code only needs to change very slightly.
Path disk = Paths.get("d:\\.");
try (ByteChannel bc = Files.newByteChannel(disk, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(10);
bc.read(buffer);
} catch (Exception e){
e.printStackTrace();
}
Is fine, workable code, but I get an access denied error in both your version and mine.
Run this as administrator. It really does work, as it's only a thin wrapper over java.io:
try (FileInputStream fis = new FileInputStream(disk);
ReadableByteChannel fc = Channels.newChannel(fis))
{
System.out.println("No exceptions! Yay!");
ByteBuffer bb = ByteBuffer.allocate(4096);
int count = fc.read(bb);
System.out.println("read count="+count);
}
catch (Exception ex)
{
System.out.println("Oh bother: "+ex);
ex.printStackTrace();
}
EDIT If you need random access, you're stuck with RandomAccessFile. There's no mapping from that via Channels. But the solution above isn't NIO anyway, just a Java NIO layer over FileInput/OutputStream.
Related
I am new to Java and I need help.
When I reopen GUI, it doesn't shows what has been saved into the file, which was serialization. The file is saving successful, but when I close and reopen and run the application it doesn't show on JList, what was saved into this file.
try
{
FileInputStream jos = new FileInputStream("jokam.ser");
GZIPInputStream gis = new GZIPInputStream(jos);
ObjectInputStream hehe = new ObjectInputStream(gis);
v1= (Vector<Vector>)hehe.readObject();
Vpredmeti.addAll((Collection<? extends Predmet>)v1.get(0));
Vvlak.addAll((Collection<? extends Vlak>)v1.get(1));
jos.close();
hehe.close();
gis.close();
v1.addAll(0, v1);
for(Predmet pr : predmetAR){
System.out.println(pr);
}
}
catch (Exception e)
{
}
}
These Vectors are before try code.
Vector <Predmet> Vpredmeti = new Vector (predmetAR);
Vector <Vlak> Vvlak= new Vector();
Vector <Vector> v1 = new Vector<>();
This is where I add to JList.
private void DodajPredmetMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
// DefaultListModel list = new DefaultListModel();
String praznoPolje=ImePredmeta.getText();
String drugoPraznoPolje=ZnacilnostPredmeta.getText();
int tretjoPraznoPolje = (int)ComboBoxZabojnika.getSelectedIndex();
Predmet novPredmet = new Predmet();
novPredmet.ime = ImePredmeta.getText();
novPredmet.znacilnosti = drugoPraznoPolje;
novPredmet.tipZabojnika=tretjoPraznoPolje;
//list.addElement(novPredmet);
predmetAR.add(novPredmet);
Save code
Vector<Predmet> Vpredmet = new Vector<>(predmetAR);
Vector<Vlak> Vvlak = new Vector<>(vlakAR);
Vector<Vector> v = new Vector<>();
v.add(0,Vpredmet);
v.add(1,Vvlak);
try
{
FileOutputStream fos = new FileOutputStream("jokam.ser");
GZIPOutputStream gos = new GZIPOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(gos);
oos.writeObject(v);
gos.close();
fos.close();
oos.close();
}
catch(Exception e)
{
}
}
Those exceptions you noted are almost definitely problems where a stream was closed early, either on the write part or the read part. It's also indicative of a layering problem with the streams, but I don't see that here.
To first step in solving these problems is making sure all the data is written before the stream is closed, and in the proper order. I usually flush() the highest level stream before closing it or underlying parts. flush() the highest level OutputStream (here, the ObjectOutputStream), and it will flush all the underlying streams (here the GZIPOutputStream and FileOutputStream). Technically close() also flush()es the stream so this may not be necessary.
Also, make sure to close() streams in the correct order. Same as flush(), close the higher level stream and the underlying streams get close()d (and flush()ed) automatically.
The code you already have close()es the GZIPOutputStream first, which precludes the closing bits of the ObjectOutputStream. Later, the ObjectOutputStream is close()d which will try to write those bits but the underlying stream has already been closed so, so an IOException is thrown.
When writing, I suggest trying just:
objectOutputStream.close();
As for the reading, just this should be good:
objectInputStream.close()
As I mentioned in the comments, you should close() in a finally block so that any Exception thrown in the try block still results in the close() being called. Be aware that close() can also throw an Exception ;)
To investigate this on your own, I suggest looking into the source code of all these streams to see what's happening inside. The JDK includes an optional jdk/lib/src.zip, which most IDE's will let you jump into. Try 'go to definition' on your objectOutputStream.close() and you should see the source code.
Stackoverflowers,
I am doing a simple project using Android smartphones to create 3D forms. I am using Android Processing to make a simple App.
My code makes a 3D shape and saves it as an .STL file. It works on my laptop and saves the .STL file, but in the App. version, I need it to save to the External storage/SD Card of my phone (HTC Sensation). It does not, because of the way the “save” function (writeSTL) in the Processing library I am using has been written.
I have posted for help here (my code more complete code is here too):
http://forum.processing.org/two/discussion/4809/exporting-geometry-stl-obj-dfx-modelbuilder-and-android
...and Marius Watz who wrote the library says that the writeSTL() code is pretty much standalone and the only thing missing is (or should be) replacing the code creating the output stream, which needs to be modified to work with Android. Basically, this line:
FileOutputStream out=(FileOutputStream)UIO.getOutputStream(p.sketchPath(filename));
I am not a great programmer in that I can usually get Processing to do what I need to do but no more; this problem has me beaten. I am looking for ideas for the correct code to replace the line:...
FileOutputStream out=(FileOutputStream)UIO.getOutputStream(p.sketchPath(filename));
...with something “Android-friendly”. Calling getExternalStorageDirectory() should work but I am at a loss to find the correct structure.
The code for the writeSTL function is below.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Output binary STL file of mesh geometry.
* #param p Reference to PApplet instance
* #param filename Name of file to save to
*/
public void customWriteSTL(UGeometry geo, PApplet p, String filename) {
byte [] header;
ByteBuffer buf;
UFace f;
try {
if (!filename.toLowerCase().endsWith("stl")) filename+=".stl";
FileOutputStream out=(FileOutputStream)UIO.getOutputStream(p.sketchPath(filename));
buf = ByteBuffer.allocate(200);
header=new byte[80];
buf.get(header, 0, 80);
out.write(header);
buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.putInt(geo.faceNum);
buf.rewind();
buf.get(header, 0, 4);
out.write(header, 0, 4);
buf.rewind();
UUtil.logDivider("Writing STL '"+filename+"' "+geo.faceNum);
buf.clear();
header=new byte[50];
if (geo.bb!=null) UUtil.log(geo.bb.toString());
for (int i=0; i<geo.faceNum; i++) {
f=geo.face[i];
if (f.n==null) f.calcNormal();
buf.rewind();
buf.putFloat(f.n.x);
buf.putFloat(f.n.y);
buf.putFloat(f.n.z);
for (int j=0; j<3; j++) {
buf.putFloat(f.v[j].x);
buf.putFloat(f.v[j].y);
buf.putFloat(f.v[j].z);
}
buf.rewind();
buf.get(header);
out.write(header);
}
out.flush();
out.close();
UUtil.log("Closing '"+filename+"'. "+geo.faceNum+" triangles written.\n");
}
catch (Exception e) {
e.printStackTrace();
}
}
Any suggestions are gratefully received.
Thank you in advance.
There are a few ways of doing this - some that will just work and some that are proper ... as with all things Processing/Java. It's really not that different from regular Java though - the only quirk is the root SD path, and checking if it exists or not (note that some phones have "internal" rather than "external" storage (i.e. not removable/swappable), but Android should interpret these the same AFAIK.
In classic Java fashion, you should really be checking IF the SD Card is present beforehand... I use the following structure, taken from this answer by #kaolick
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
// Storage is available and writeable - ALL GOOD
} else if (state.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
// Storage is only readable - RUH ROH
} else {
// Storage is neither readable nor writeable - ABORT
}
Note that he provides a full class for you to use, which is great, and has a few convenience functions.
The second thing you might want to look at is creating a custom directory on the SD Card of the device, probably in setup() - something like this:
try{
String dirName = "//sdcard//MyAppName";
File newFile = new File(dirName);
if(newFile.exists() && newFile.isDirectory()) {
println("Directory Exists... All Good");
}
else {
println("Directory Doesn't Exist... We're Making It");
newFile.mkdirs();
}
}
catch(Exception e) {
e.printStacktrace();
}
Of course, instead of HardCoding the Path name, you should do something like
String dirName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyAppName";
instead...
Also, note that the above try/catch should go INSIDE the case statement of "if (state.equals(Environment.MEDIA_MOUNTED))" ... or should be wrapped in a separate function anc called from there.
Then, finally, saving it. If you wanted to use a BufferedWriter, it would look like this:
BufferedWriter writer = new BufferedWriter(new FileWriter(dirName, true));
writer.write(STL_STUFF);
writer.flush();
writer.close();
I've only use a FileOutputStream within a BufferedOutput Stream, and it looked like this:
try {
String fileName = "SOME_UNIQUE_NAME_PER_FILE";
String localFile = dirName + "/" +filename;
OutputStream output = new BufferedOutputStream(newFileOutputStream(localFile));
}
catch(Exception e) {
e.printStackTrace();
}
Finally, give my regards to Marius if you talk to him! ;-)
Hi Stackoverflow members,
for some time we switched in out GWT application, the GWT version from 2.4 to 2.6.
So we also changed to the new super dev mode there. With this we needed to install
an local jetty server and could not use the internal eclipse ?jetty? anymore.
On the server side we are writing and saving images with the ImageIO package from
sun itself. Till last week, there were no problems with this, but then we checked
that our app is not anymore able to read from bytearrayinputstream in the case as
it does on our deployment servers. For reliable development we need the possibility
to code and test on a local platform.
The problem is, that ImageIO.read static function does not work anymore, but it
does not only don't work anymore, it exits the code WITHOUT to throw an exception!
I will now show you the code part:
System.out.println("createImage..."+file+", "+response+", fib"+fileInBytes+" fibs:"+fileInBytes.length);
ETFile f = file;
boolean isImage = false;
BufferedImage image = null;
try {
System.out.println("read1...");
ByteArrayInputStream bais = new ByteArrayInputStream(fileInBytes);
System.out.println("read2..."+bais);
image = ImageIO.read(bais);
//ByteArrayOutputStream baos = new ByteArrayOutputStream();
//baos.write(fileInBytes);
//saveStreamToFile(filename+"_bla.jpg", baos, data);
//baos.close();
bais.close();
System.out.println("read2.5...");
if (image != null) {
System.out.println("read2.6...");
isImage = true;
}
System.out.println("read3...");
} catch (/*IO*/Exception e) {
System.out.println("read4...");
System.out.println(e.getLocalizedMessage());
e.printStackTrace();
} finally {
System.out.println("read4.5...");
}
System.out.println("isimage:"+isImage);
I'm getting only the following output:
read1...
read2...java.io.ByteArrayInputStream#15bea4b
But no:
System.out.println("read2.5...");
System.out.println("read2.6...");
System.out.println("read3...");
System.out.println("read4...");
nor
System.out.println("read4.5...");
As you see, i can write the bytestream s file to filesystem, but
can't read that bytestream with ImageIO.read to an image.
And I don't know why. The bytestream is there, has a size and writing
it to disk is also correct, but if I use ImageIO.read the server somehow
exits the code without any exception..
Do someone know, was is going wrong here?
Thank you.
Regards,
Max
edit attached stack trace
thread:1323900765#qtp-433064372-0:java.lang.ClassLoader$NativeLibrary.load(Native Method)
thread:1323900765#qtp-433064372-0:java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1833)
thread:1323900765#qtp-433064372-0:java.lang.ClassLoader.loadLibrary(ClassLoader.java:1730)
thread:1323900765#qtp-433064372-0:java.lang.Runtime.loadLibrary0(Runtime.java:823)
thread:1323900765#qtp-433064372-0:java.lang.System.loadLibrary(System.java:1044)
thread:1323900765#qtp-433064372-0:sun.security.action.LoadLibraryAction.run(LoadLibraryAction.java:50)
thread:1323900765#qtp-433064372-0:java.security.AccessController.doPrivileged(Native Method)
thread:1323900765#qtp-433064372-0:java.awt.Toolkit.loadLibraries(Toolkit.java:1605)
thread:1323900765#qtp-433064372-0:java.awt.Toolkit.<clinit>(Toolkit.java:1627)
thread:1323900765#qtp-433064372-0:sun.awt.AppContext$2.run(AppContext.java:240)
thread:1323900765#qtp-433064372-0:sun.awt.AppContext$2.run(AppContext.java:226)
thread:1323900765#qtp-433064372-0:java.security.AccessController.doPrivileged(Native Method)
thread:1323900765#qtp-433064372-0:sun.awt.AppContext.initMainAppContext(AppContext.java:226)
thread:1323900765#qtp-433064372-0:sun.awt.AppContext.access$200(AppContext.java:112)
thread:1323900765#qtp-433064372-0:sun.awt.AppContext$3.run(AppContext.java:306)
thread:1323900765#qtp-433064372-0:java.security.AccessController.doPrivileged(Native Method)
thread:1323900765#qtp-433064372-0:sun.awt.AppContext.getAppContext(AppContext.java:287)
thread:1323900765#qtp-433064372-0:javax.imageio.spi.IIORegistry.getDefaultInstance(IIORegistry.java:137)
thread:1323900765#qtp-433064372-0:javax.imageio.ImageIO.<clinit>(ImageIO.java:48)
thread:1323900765#qtp-433064372-0:com.et.eb.server.servlets.ETFileUploadServlet.createImage(ETFileUploadServlet.java:441)
thread:1323900765#qtp-433064372-0:com.et.eb.server.servlets.ETFileUploadServlet.writeImage(ETFileUploadServlet.java:285)
thread:1323900765#qtp-433064372-0:com.et.eb.server.servlets.ETFileUploadServlet.readFormData(ETFileUploadServlet.java:364)
thread:1323900765#qtp-433064372-0:com.et.eb.server.servlets.ETFileUploadServlet.doPost(ETFileUploadServlet.java:122)
thread:1323900765#qtp-433064372-0:javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
thread:1323900765#qtp-433064372-0:javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:401)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.Server.handle(Server.java:326)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:945)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
thread:1323900765#qtp-433064372-0:org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
thread:1323900765#qtp-433064372-0:org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
thread:1323900765#qtp-433064372-0:org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
I'm having issues with reading decrypted data from conceal. It looks like I can't correctly finish streaming.
I pretend there is some issue with conceal, because of when I switch my proxyStream (just the encryption part) to not run it through conceal, everything works as expected. I'm also assuming that writing is ok, there is no exception whatsoever and I can find the encrypted file on disk.
I'm proxying my data through contentprovider to allow other apps read decrypted data when the user wants it. (sharing,...)
In my content provider I'm using the openFile method to allow contentResolvers read the data
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
try {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
String name = uri.getLastPathSegment();
File file = new File(name);
InputStream fileContents = mStorageProxy.getDecryptInputStream(file);
ParcelFileDescriptor.AutoCloseOutputStream stream = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);
PipeThread pipeThread = new PipeThread(fileContents, stream);
pipeThread.start();
return pipe[0];
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
I guess in the Facebook app Facebook android team could be rather using a standard query() method with a byte array sent in MediaStore.MediaColumns() which is not suitable for me because of I'm not only encrypting media files and I also like the approach of streams better.
This is how I'm reading from the Inpustream. It's basically a pipe between two parcelFileDescriptors. The inputstream comes from conceal and it is a FileInputstream wrapped into a BufferedInputStream originaly.
static class PipeThread extends Thread {
InputStream input;
OutputStream out;
PipeThread(InputStream inputStream, OutputStream out) {
this.input=inputStream;
this.out=out;
}
#Override
public void run() {
byte[] buf=new byte[1024];
int len;
try {
while ((len=input.read(buf)) > 0) {
out.write(buf, 0, len);
}
input.close();
out.flush();
out.close();
}
catch (IOException e) {
Log.e(getClass().getSimpleName(),
"Exception transferring file", e);
}
}
}
I've tried other methods how to read the stream, so it really shouldn't be the issue.
Finally here's the exception I'm constantly ending up with. Do you know what could be the issue? It points to native calls, which I got lost in..
Exception transferring file
com.facebook.crypto.cipher.NativeGCMCipherException: decryptFinal
at com.facebook.crypto.cipher.NativeGCMCipher.decryptFinal(NativeGCMCipher.java:108)
at com.facebook.crypto.streams.NativeGCMCipherInputStream.ensureTagValid(NativeGCMCipherInputStream.java:126)
at com.facebook.crypto.streams.NativeGCMCipherInputStream.read(NativeGCMCipherInputStream.java:91)
at com.facebook.crypto.streams.NativeGCMCipherInputStream.read(NativeGCMCipherInputStream.java:76)
EDIT:
It looks like the stream is working ok, but what fails is the last iteration of reading from it. As I'm using buffer it seems like the fact that the buffer is bigger then the amount of remaiming data is causing the issue. I've been looking into sources of conceal and it seems to be ok from this regard there. Couldn't it be failing somewhere in the native layer?
Note: I've managed to get the decrypted file except its final chunk of bytes..So I have for example an incomplete image file (with last few thousands of pixels not being displayed)
From my little experience with conceal, I have noticed that, only the same application that encrypts a file could decrypt it successfully irrespective whether it has the same package or not. Be sure to put this in mind
This was resolved in https://github.com/facebook/conceal/issues/24. For posterity's sake, the problem here is that the author forgot to call close() on the output stream.
I am programming a blackberry app that reads small files stored on the device.
For some reason DataInputStream will only read files that are bigger then 3kb (my estimate after a couple of test). Anyone know why this may be the case?
try
{
fconn = (FileConnection)Connector.open(seedDataLocation);
if (fconn.exists())
{
UiApplication.getUiApplication().getActiveScreen().add(new RichTextField("Read?: " + fconn.canRead()));
UiApplication.getUiApplication().getActiveScreen().add(new RichTextField("Write?: " + fconn.canWrite()));
UiApplication.getUiApplication().getActiveScreen().add(new RichTextField("Open?: " + fconn.isOpen()));
int dataSize = (int) fconn.fileSize();
DataInputStream dis = fconn.openDataInputStream();
UiApplication.getUiApplication().getActiveScreen().add(new RichTextField("Data Available: " + dataSize));
byte[] b = new byte[dataSize];
dis.readFully(b);
String data = new String(b);
UiApplication.getUiApplication().getActiveScreen().add(new RichTextField("Data: " + data));
fconn.close();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
UiApplication.getUiApplication().getActiveScreen().add(new RichTextField(e.getMessage()));
}
edit: I tried doing dis.available(); and it is returning 0 for small files in which it does not read from the file and also 0 from bigger files it will read from. Which is confusing because it is supposed to read the amount of bytes in the file.
That getActiveScreen().add call is error prone, and it will fail if you try to call it from outside the GUI thread. The fact that it is working for you means that you are actually making these calls from the GUI thread, which is horrible practice since you are also opening a file from there.
Move the connection code to another worker thread and access the GUI as needed using UiApplication.invokeLater or UiApplication.invokeAndWait to wrap your GUI-related code inside the parameter Runnables. Or either use synchronized(application.getEventLock().
That said, the fact that you are not reading data in small files only could be caused by this line:
dis.readFully(b);
Maybe you need to flush the stream. This call will block until b.length bytes are available. Check before that file is readable with fconn.isReadable.
UPDATE:
You can try also IoUtilities.streamToBytes(dis), but do not use it with big files or you can get an out-of-memory error.