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.
Related
Is there anyway to reuse an inputStream by changing its content? (Without new statement).
For instance, I was able to something very close to my requirement, but not enough
In the following code I am using a SequenceInputStream, and everytime I am adding a new InputStream to that sequence.
But I would like to do the same thing by using the same inputStream (I don't care which implementation of InputStream).
I thought about mark()/reset() APIs, but i still need to change the content to be read.
The idea to avoid new InputStream creations is because of performance issues
//Input Streams
List<InputStream> inputStreams = new ArrayList<InputStream>();
try{
//First InputStream
byte[] input = new byte[]{24,8,102,97};
inputStreams.add(new ByteArrayInputStream(input));
Enumeration<InputStream> enu = Collections.enumeration(inputStreams);
SequenceInputStream is = new SequenceInputStream(enu);
byte [] out = new byte[input.length];
is.read(out);
for (byte b : out){
System.out.println(b);//Will print 24,8,102,97
}
//Second InputStream
input = new byte[]{ 4,66};
inputStreams.add(new ByteArrayInputStream(input));
out = new byte[input.length];
is.read(out);
for (byte b : out){
System.out.println(b);//will print 4,66
}
is.close();
}catch (Exception e){//
}
No, You can't restart reading the input stream after it reaches to the end of the stream as it is uni-directional i.e. moves only in single direction.
But Refer below links, they may help:
How to Cache InputStream for Multiple Use
Getting an InputStream to read more than once, regardless of markSupported()
You could create your own implementation (subclass) of InputStream that would allow what you require. I doubt there is an existing implementation of this.
I highly doubt you'll get any measurable performance boost from this though, there's not much of logic in e.g. FileInputStream that you wouldn't need to perform anyways, and Java is well optimized for garbage-collecting short-lived objects.
I have a program I'm making for a small business which is implementing serializable on a linkedList to save data. This all works fine, until I have two staff members try and add more data to the list and one ends up overwriting the other.
JButton btnSaveClientFile = new JButton("Save Client File");
btnSaveClientFile.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
// add new items to list
jobList.add(data);
.
.
.
Controller.saveData();
}
});
btnSaveClientFile.setBounds(10, 229, 148, 23);
frame.getContentPane().add(btnSaveClientFile);
This method results in one overwriting the other, so I tried doing it like this
JButton btnSaveClientFile = new JButton("Save Client File");
btnSaveClientFile.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
Controller.retrieveData();
// add new items to list
jobList.add(data);
.
.
.
Controller.saveData();
}
});
btnSaveClientFile.setBounds(10, 229, 148, 23);
frame.getContentPane().add(btnSaveClientFile);
And when I use this one, I get no data added to the list at all. Here are my Serialization methods. This one is used to save my data.
// methods to serialize data
public static void saveData() {
System.out.println("Saving...");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream("Data.bin");
oos = new ObjectOutputStream(fos);
oos.writeObject(myOLL);
oos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
And this one is used to collect my data
public static void retrieveData() {
// Get data from disk
System.out.println("Loading...");
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("Data.bin");
ois = new ObjectInputStream(fis);
myOLL = (OrderedLinkedList) ois.readObject();
ois.close();
} catch (Exception ex) {
System.err.println("File cannot be found");
ex.printStackTrace();
}
}
How do I make it so I can save data to my file from two different computers at a similar time, without one overwriting the other?
This is a demo (and not meant to be used in this crude way) how to acquire a lock on file /tmp/data.
RandomAccessFile raf = new RandomAccessFile( "/tmp/data", "rw" );
FileChannel chan = raf.getChannel();
FileLock lock = null;
while( (lock = chan.tryLock() ) == null ){
System.out.println( "waiting for file" );
Thread.sleep( 1000 );
}
System.out.println( "using file" );
Thread.sleep( 3000 );
System.out.println( "done" );
lock.release();
Clearly, reading a sequential file, mulling over it for some time and then rewriting or not is prohibitive if you require a high level of concurrency. That's why such applications typically use database systems, the client-server paradigm. A free-for-all on the file system isn't tolerable except in rare circumstances. Your organization may be able to assign updates of the data to one person at a time, which would simplify matters.
add more data to the list and one ends up overwriting the other.
This is how files work by default, in fact the ObjectOutputStream doesn't support an "append" mode. Once you have closed the stream, you can't alter it.
How do I make it so I can save data to my file from two different computers at a similar time, without one overwriting the other?
You have two problems here
how to write to a file twice without losing information.
how to co-ordinate writes between processes without one impacting the other.
For the first part, you need to read the contents of the list first, add the entries you wand to add, and write out the contents again. OR you can change the file format to one which supports appending.
For the second part, you need to use locking of some kind. A simple way to do this is to create a lock file. You can create a second file atomically e.g. file.lock and the one which succeeds in creating the file holds the lock, that process alters the file and deletes the lock which finished. Some care needs to be taken to ensure you always remove the lock.
Another approach is to use file locks. You have to take care not to delete the file in the process however this has the benefit that the OS will clean up the lock if your process dies.
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'm trying to print objects into file.
Then I want to import them back to my program.
ObjectOutputStream not working, What am I missing? (try, catch not visible here but they're doing their job)
Map< Account, Customer> customerInfo = new HashMap< Account, Customer>();
File bankFile = new File("Bank.txt");
FileOutputStream fOut = new FileOutputStream( bankFile);
ObjectOutputStream objOut = new ObjectOutputStream(fOut);
for(Map.Entry<Account, Customer> e : bank.customerInfo.entrySet())
{
objOut.writeObject(e.getValue());
objOut.writeObject(e.getKey());
}
objOut.flush();
objOut.close();
fOut.close();
My problem here is that ObjectOutputStream is not working properly, it prints some weird code. I've used other methods to print out to file and they work just fine.
I've tried printing to different file extensions,
I tried changing the encoding for both the file and eclipse.
I tried different methods for getting the info from the Map using ObjectOutputStream. Is there a reason why ObjectOutputStream prints weird characters that I haven't think of? The entire file is almost impossible to read. Thanks!
Ps. some of the weird print, don't know if it helps.
¬ísrCustomerDìUðkJ
personalIdNumLnametLjava/lang/String;xpthellosr
SavingAccountUÞÀÀ;>ZfreeWithdrawDwithdrawalInterestRateLaccountTypeq~xrAccount é=UáÐI
accountNumberDbalanceDinterestRateLaccountTypeq~L transListtLjava/util/List;xpé?záG®{tsrjava.util.ArrayListxÒÇaIsizexpw
x?záG®{tSaving Accountq~sr
CreditAccountÝ
*5&VcLaccountTypeq~xq~ê?záG®{q~sq~ w
xtCredit Account
It's really quite simple. First things first, create a class that implements Serializable. Serializable is a marker interface, so you don't need to implement any methods for it:
public class Shoe implements Serializable { ... }
NOTE: If Shoe has other classes in it, for example Heel, or Buckle, those classes also need to implement the Serializable interface.
Next step is to write that to a file, using an ObjectOutputStream.
FileOutputStream out = new FileOutputStream("myfile.txt");
// Create the stream to the file you want to write too.
ObjectOutputStream objOut = new ObjectOutputStream(out);
// Use the FileOutputStream as the constructor argument for your object.
objOut.writeObject(new Shoe("Prada"));
// Write your object to the output stream.
objOut.close();
// MAKE SURE YOU CLOSE to avoid memory leaks, and make sure it actually writes.
There you have it. The serialized object is written to the txt file. Now to read it, it's just a case of using the ObjectInputStream.
ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("myfile.txt");
Object obj = objIn.readObject();
if(obj instanceof Shoe)
{
Shoe shoe = (Shoe)obj;
}
And you've got an object you can use.
I get a file personHashMap.ser with a HashMap in it. Here's the code how i create it:
String file_path = ("//releasearea/ToolReleaseArea/user/personHashMap.ser");
public void createFile(Map<String, String> newContent) {
try{
File file = new File(file_path);
FileOutputStream fos=new FileOutputStream(file);
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(newContent);
oos.flush();
oos.close();
fos.close();
}catch (Exception e){
System.err.println("Error in FileWrite: " + e.getMessage());
}
}
Now i want, when the program is running, that all five minutes update the file personHashMap.ser only with the content which changed. So the method i called:
public void updateFile(Map<String, String> newContent) {
Map<String, String> oldLdapContent = readFile();
if(!oldLdapContent.equals(ldapContent)){ // they arent the same,
// so i must update the file
}
}
But now i haven't any ideas how i can realise that.
And is it better for the performance to update only the new content or should i clean the full file and insert the new list again?
Hope you can Help me..
EDIT:
The HashMap includes i.e street=Example Street.
But now, the new street called New Example Street. Now i must update the HashMap in the File. So i can't just append the new content...
Firstly HashMap isn't really an appropriate choice. It's designed for in-memory usage, not serialization (though of course it can be serialized in the standard way). But if it's just 2kb, then go ahead and write the whole thing rather than the updated data.
Second, you seem to be overly worried about performance of this rather trivial method (for 2kb the write will take mere milliseconds). I would be worried more about consistency and concurrency issues. I suggest you look into using a lightweight database such as JavaDB or h2.
Use the constructor FileOutputStream(File file, boolean append), set the boolean append to true. It will append the text in the existing file.
You can call the updateFile method in a loop and then call sleep for 5 minutes (5*60*1000 ms).
Thread.Sleep(300000); // sleep for 5 minutes
To append to your already existing file you can use :
FileOutputStream fooStream = new FileOutputStream(file, true);