Update Serialized Object in Java - java

Is there a way to read a serialized object from a .ser file and update or delete one of the objects that have been serialized?
The following is my code which read's in objects of type 'Driver':
public boolean checkPassword(String userName, String password, String depot) throws IOException {
FileInputStream fileIn = new FileInputStream("Drivers.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
try
{
while (true) {
Driver d = (Driver) in.readObject();
if (d.userName.equals(userName) && d.password.equals(password) && d.depot.equals(depot))
{
this.isManager = d.isManager;
validAccount = true;
}
}
}
catch (Exception e) {}
return validAccount;
}

You will need to read all objects from the original file and then write a new file containing only the objects you want to retain or update.
The Java serialized object stream format is not an archive file format like ZIP, JAR, TAR and so on. It is just a sequence of serialized objects. There is no "index" that would facilitate updating or deleting objects.
This is one reason why serialized objects are not a good way to implement data persistence. This is what databases are designed for.

Related

How do I handle storage in a Java console app that cannot use DB?

I am given an assignment where we are not allowed to use a DB or libraries but only textfile for data storage.
But it has rather complex requirements, for e.g. many validations, because of that, we need to "access the db" (i.e. read the textfile) many times.
My question is: should I create a class like this:
class SomeRepository{
static ArrayList<Users> users = new ArrayList();
public SomeRepository(){
//instantiate this class on program load
//In constructor, we read the text file, instantiate and store everything inside the arraylist.
}
//public getOneUser(){ // for get methods, we don't read from text file at all }
/public save() { //text file saving code overhere }
}
Is this a good approach to solve the above problem? Currently, what we are doing is reading and writing to the text file every time we want to retrieve some data or write something new.
Wouldn't this be too expensive in terms of heap space memory? Or should I just read/write to the text file for every method?
public class IOManager {
public static void writeObjToTxtFile(String fileName, Object object) {
File file = new File(fileName + ".txt");//File will be created in the root directory where the program runs.
try (FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(object);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object readObjFromTxtFile(String fileName) {
Object obj = null;
File file = new File(fileName + ".txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
obj = ois.readObject();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return obj;
}
}
Add this class to your project. Since it's general for all Objects, you can pass and receive Objects like these as well: ArrayList<Users>. Play around and Tinker with it to fit whatever your specific purpose is. Hint: You can write other custom methods that calls these methods. eg:
public static void writeUsersToFile(ArrayList<Users> usersArrayList){
writeObjToTxtFile("users",usersArrayList);
}
Ps. Make sure your Objects implement Serializable. Eg:
public class Users implements Serializable {
}
I would suggest reading the contents of your file to a dynamic list such as an arraylist at the start of your program. Make the required queries/changes to your arraylist and then write that arraylist to your file when the program is set to close. This will save significant time over repeated file reads/writes.
This isn't without it's drawbacks, though. You don't want to hogg up memory in case of very large files - but considering this is an assignment, that may not be the case. Additionally, should your program terminate prior to the write at the end, all changes made to your database during the current execution will be lost.

Writing Strings to a binary file java

I have a list of objects that has some simple String properties. I want to be able to save those strings to binary so that when you open the file outside the program, you only see 1's and 0's.
I have managed to use FileOutputStreamand saved the strings, however, I can't manage to get it to write to binary. The file reads as clean readable text. I have tried getBytes().
What would be the best approach for this? Keep in mind that I want to be able to read the file later and construct back the objects. Would it be better to use Serializable and save a list of objects?
Here is my FileWriter:
NB: The toString() is custom and returns a String with linebreaks for every property.
public class FileWriter {
public void write(String fileName, Savable objectToSave ) throws IOException {
File fileToSave = new File(fileName);
String stringToSave = objectToSave.toString();
byte[] bytesToSave = stringToSave.getBytes(StandardCharsets.UTF_8) ;
try (
OutputStream outputStream = new FileOutputStream(fileToSave);
) {
outputStream.write(bytesToSave);
} catch (IOException e) {
throw new IOException("error");
}
}
}
If your goal is simply serializing, implementing Serializable and writing them would work, but your string is still going to be readable. You can encrypt the stream, but anyone decompiling your code can still devise a way to read the values.

Read PDVInputStream dicomObject information on onCStoreRQ association request

I am trying to read (and then store to 3rd party local db) certain DICOM object tags "during" an incoming association request.
For accepting association requests and storing locally my dicom files i have used a modified version of dcmrcv() tool. More specifically i have overriden onCStoreRQ method like:
#Override
protected void onCStoreRQ(Association association, int pcid, DicomObject dcmReqObj,
PDVInputStream dataStream, String transferSyntaxUID,
DicomObject dcmRspObj)
throws DicomServiceException, IOException {
final String classUID = dcmReqObj.getString(Tag.AffectedSOPClassUID);
final String instanceUID = dcmReqObj.getString(Tag.AffectedSOPInstanceUID);
config = new GlobalConfig();
final File associationDir = config.getAssocDirFile();
final String prefixedFileName = instanceUID;
final String dicomFileBaseName = prefixedFileName + DICOM_FILE_EXTENSION;
File dicomFile = new File(associationDir, dicomFileBaseName);
assert !dicomFile.exists();
final BasicDicomObject fileMetaDcmObj = new BasicDicomObject();
fileMetaDcmObj.initFileMetaInformation(classUID, instanceUID, transferSyntaxUID);
final DicomOutputStream outStream = new DicomOutputStream(new BufferedOutputStream(new FileOutputStream(dicomFile), 600000));
//i would like somewhere here to extract some TAGS from incoming dicom object. By trying to do it using dataStream my dicom files
//are getting corrupted!
//System.out.println("StudyInstanceUID: " + dataStream.readDataset().getString(Tag.StudyInstanceUID));
try {
outStream.writeFileMetaInformation(fileMetaDcmObj);
dataStream.copyTo(outStream);
} finally {
outStream.close();
}
dicomFile.renameTo(new File(associationDir, dicomFileBaseName));
System.out.println("DICOM file name: " + dicomFile.getName());
}
#Override
public void associationAccepted(final AssociationAcceptEvent associationAcceptEvent) {
....
#Override
public void associationClosed(final AssociationCloseEvent associationCloseEvent) {
...
}
I would like somewhere between this code to intercept a method wich will read dataStream and will parse specific tags and store to a local database.
However wherever i try to put a piece of code that tries to manipulate (just read for start) dataStream then my dicom files get corrupted!
PDVInputStream is implementing java.io.InputStream ....
Even if i try to just put a:
System.out.println("StudyInstanceUID: " + dataStream.readDataset().getString(Tag.StudyInstanceUID));
before copying datastream to outStream ... then my dicom files are getting corrupted (1KB of size) ...
How am i supposed to use datastream in a CStoreRQ association request to extract some information?
I hope my question is clear ...
The PDVInputStream is probably a PDUDecoder class. You'll have to reset the position when using the input stream multiple times.
Maybe a better solution would be to store the DICOM object in memory and use that for both purposes. Something akin to:
DicomObject dcmobj = dataStream.readDataset();
String whatYouWant = dcmobj.get( Tag.whatever );
dcmobj.initFileMetaInformation( transferSyntaxUID );
outStream.writeDicomFile( dcmobj );

How do you check what type of data is in a file

I am writing data with types as int, char, double, byte, and boolean to and from files.
I have the methods that write my data to the files.
For the reading method, I am having the content of the files put into an ArrayList and then transferring them into a plain array. However in order to do that I have to know what the data type of the file's contents are.
So my question here is:
How do I check to see what the data type of the contents of a random file is?
You access files via Streams.
What you read out of a file depends on the stream-class you use to access the file.
There are two main groups in Java (up to Java 7):
1. The "...Reader" classes. Here the content of the file is read as sequence of chars.
2. The "...Stream" classes. Here the content of the file is read as a sequence of bytes.
However, you can write and read Java Objects to and from a file "directly" via the ObjectOutputStream and the ObjectInputStream classes. With them you ca read/write serialized Java-objects and primitive datatypes. With this you could check what you want in the following way:
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("filename"));
Object o = ois.readObject();
if (o instanceof)
//... checked
(This only works if the content of the file are serialized java objects.)
There's is no simple generic way to do this automatically.
If you want to retain additional information as the type, you will have to store it along with the data.
Here are some examples of how you can store the type info.
Using annotation. Always store the type explicitly with the related data, e.g. if the first token on a line is equal to "type3" then the following data represents a floating point number (for example).
type1 herecomesthedata1
type2 11011010111011010
type3 55.67
For more complex data with trees of variables use a well known data annotation standard as JSON or XML.
Using structure. Always have the variables written in the same order, e.g. the first token on a line is always an integer and the next is always floating point etc. Use this information when reading the data.
123 43.11
456 78.90
Use Java's built in serialization utilites as ObjectOutputStream and ObjectInputStream (only works on primitive types and objects that implement java.io.Serializable).
Example (using structure to determine type):
int i = 5;
double d = 7.3;
try (ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("test.dat"))) {
out.writeInt(i);
out.writeDouble(d);
} catch (IOException e) {
System.err.println("An error occured writing to file");
}
i = 0;
d = 0.0;
try (ObjectInputStream in = new ObjectInputStream(
new FileInputStream("test.dat"))) {
i = in.readInt();
d = in.readDouble();
} catch (IOException e) {
System.err.println("An error occured reading from file");
}
System.out.println("i = " + i + " and d = " + d); // 5 and 7.3

Java Serializing: One object per file

For this specific project I need to serialize my entity layer (made of POJO's) to files. As I have the need for updating specific objects I would like to use one file per serialized object.
Example: Customer --ArrayList-> Order --ArrayList-> Product
When I edit a customer, and then serialize it using the java.io.Serializable interface, all fields, and their fields (please correct me if wrong), get serialized.
How would I apply serialization in such a way that only one object per file is used? I already have given each object a uniqe UUID which is used as filename when serializing.
If there are any frameworks that do File based ORM, that would be even better ;)
I'm not familiar with such framework.
What you can do is use other frameworks such as apache BeanUtils in order to perform the following recursive algorithm:
A. For each object gets its properties (assuming the object is a Java bean).
B. For each primitive field , write all primitives to file (you can use reflection to determine if a field is primitive or not).
C. For each non primitive file, write a special section in the file, pointing to the file name that will contain the object that is the value of the field.
D. Call recursively the algorithm for each non primitive field.
Similar approach can be done for collections -
HashMap, ArrayList and others.
The serializing code for the primitive elements can be the code provided by #Anshu
You can always read and write serializable objects using readObject and writeObject. Following is the example code:
import java.io.*;
import java.util.*;
import java.util.logging.*;
public class ExerciseSerializable {
public static void main(String... aArguments) {
//create a Serializable List
List<String> quarks = Arrays.asList(
"up", "down", "strange", "charm", "top", "bottom"
);
//serialize the List
//note the use of abstract base class references
try{
//use buffering
OutputStream file = new FileOutputStream( "quarks.ser" );
OutputStream buffer = new BufferedOutputStream( file );
ObjectOutput output = new ObjectOutputStream( buffer );
try{
output.writeObject(quarks);
}
finally{
output.close();
}
}
catch(IOException ex){
fLogger.log(Level.SEVERE, "Cannot perform output.", ex);
}
//deserialize the quarks.ser file
//note the use of abstract base class references
try{
//use buffering
InputStream file = new FileInputStream( "quarks.ser" );
InputStream buffer = new BufferedInputStream( file );
ObjectInput input = new ObjectInputStream ( buffer );
try{
//deserialize the List
List<String> recoveredQuarks = (List<String>)input.readObject();
//display its data
for(String quark: recoveredQuarks){
System.out.println("Recovered Quark: " + quark);
}
}
finally{
input.close();
}
}
catch(ClassNotFoundException ex){
fLogger.log(Level.SEVERE, "Cannot perform input. Class not found.", ex);
}
catch(IOException ex){
fLogger.log(Level.SEVERE, "Cannot perform input.", ex);
}
}
// PRIVATE //
//Use Java's logging facilities to record exceptions.
//The behavior of the logger can be configured through a
//text file, or programmatically through the logging API.
private static final Logger fLogger =
Logger.getLogger(ExerciseSerializable.class.getPackage().getName())
;
}

Categories