Can we write a Hashtable to a file? - java

I have a Hashtable<string,string>, in my program I want to record the values of the Hashtable to process later.
My question is: can we write object Hastable to a file? If so, how can we later load that file?

Yes, using binary serialization (ObjectOutputStream):
FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(yourHashTable);
oos.close();
Then you can read it using ObjectInputStream
The objects that you put inside the Hashtable (or better - HashMap) have to implement Serializable
If you want to store the Hashtable in a human-readable format, you can use java.beans.XMLEncoder:
FileOutputStream fos = new FileOutputStream("tmp.xml");
XMLEncoder e = new XMLEncoder(fos);
e.writeObject(yourHashTable);
e.close();

Don't know about your specific application, but you might want to have a look at the Properties class. (It extends hashmap.)
This class provides you with
void load(InputStream inStream)
Reads a property list (key and element pairs) from the input byte stream.
void load(Reader reader)
Reads a property list (key and element pairs) from the input character stream in a simple line-oriented format.
void loadFromXML(InputStream in)
Loads all of the properties represented by the XML document on the specified input stream into this properties table.
void store(Writer writer, String comments)
Writes this property list (key and element pairs) in this Properties table to the output character stream in a format suitable for using the load(Reader) method.
void storeToXML(OutputStream os, String comment)
Emits an XML document representing all of the properties contained in this table.
The tutorial is quite educational also.

If you want to be able to easily edit the map once it's written out, you might want to take a look at jYaml. It allows you to easily write the map to a Yaml-formatted file, meaning it's easy to read and edit.

You could also use MapDB and it will save the HashMap for you after you do a put and a commit.
That way if the program crashes the values will still be persisted.

Related

Edit an inputstream and write it out as a stream without storing all of its contents into memory at any given time

I have a method that is receiving an InputStream of data in JSON format. Using Jackson's ObjectMapper, I am able to convert the InputStream into a JsonNode that I can edit, like so:
JsonNode revisions = mapper.readTree(data);
From there, I am able to iterate through each element and make my changes. In doing so, though, I am storing all the elements in a list and then converting the list to a Stream. I would prefer to operate on each element one at a time from the InputStream, that way I don't have to store it all in memory.
Here's what I have:
public Stream<Revision> jsonToRevisionObjects(InputStream allData) throws IOException {
// convert the InputStream to a JsonNode
JsonNode revisions = mapper.readTree(allData);
List<Revision> newRevisions = new ArrayList<>();
for (JsonNode revision : revisions.get("results")) {
// create Revision objects and add them to newRevisions
}
return newRevisions.stream();
}
This essentially defies the point of even using Stream since I'm storing all the new Revision objects into memory. Instead, I'd like to read one element at a time and send it off to the stream before loading in the next element. Is there a way of doing this? Based on surrounding code, the input parameter will always be an InputStream (there lies the problem) and the return type will always be Stream.
this might be possible if I was able to convert an InputStream into a Stream and do the following:
return allDataStream.map(rev -> {
// create Revision object
});
but I'm not sure how to get to that point if it's a possibility.
To use streaming reads, you must use JsonParser, either directly, or by passing it to ObjectMapper/ObjectReader. If so, you may read sub-trees as JsonNode if you want to.
To construct a JsonParser from InputStream is simple:
JsonParser p = mapper.getFactory().createParser(inputStream);
but operation after this varies; you can either read token-stream directly from JsonParser, or ask ObjectMapper or ObjectReader to read next "value" from stream. And then the structure of JSON data matters; you may need to advance parser's stream (nextToken()) if you want to avoid reading all the contents.

How to load a csv file to an ArrayList <Object Type> while the other array is of strings?

The method below is used to load the CSV file into an array of Strings, I want to store the elements in the created array into an ArrayList<Attack> where Attack is an abstract class. I have about 3 CSV files each should be loaded into an ArrayList of the other class types, so how would I implement it ?
private static String[] loadCSV(String filePath) throws IOException
{
String currentLine="";
String[] tmp = null;
FileReader fileReader=new FileReader(filePath);
BufferedReader br=new BufferedReader(fileReader);
while((currentLine=br.readLine())!=null)
tmp = currentLine.split(",");
return tmp;
}
As explained in the comments, CSV-parsing is far from trivial, and should be delegated to a proven library.
This problem (reading, parsing, and data-binding) seems a perfect fit for Jackson's CSV Data format module:
Jackson data format module for reading and writing CSV encoded data,
either as "raw" data (sequence of String arrays), or via data binding
to/from Java Objects (POJOs).
There are lots of examples, so rather than pick one, I'd suggest reading the article, considering the possibilities, and deciding which works best for your needs.

How to append contents of two word document?

Reading a word document for example SampleOne.doc and storing it in to a byte[].
#Column(name = "LETTER_WORD_EDITOR_VALUE")
private byte[] letterWordEditorValue;
It is a blob in DB.
I want to read the contents of another word document for Example SampleTwo.doc as byte[] and appending both the byte[] and setting the resultant byte[] in to letterWordEditorValue.
Below is the code to do that.
FileInputStream fileRead = new FileInputStream(fileNameWithPath);
byte[] readData=IOUtils.toByteArray(fileRead);
byte[] one = readData;
byte[] two = inquiryCor.getLetterWordEditorValue();
byte[] combined = new byte[one.length + two.length];
System.arraycopy(one,0,combined,0,one.length);
System.arraycopy(two,0,combined,one.length,two.length);
inquiryCor.setLetterWordEditorValue(combined);
Below is the code to read the letterWordEditorValue and writing in to a Word-File.
fileEditOutPutStream = new FileOutputStream(fileNameWithPath);
fileEditOutPutStream.write(inquiryCor.getLetterWordEditorValue());
fileEditOutPutStream.close();
The contents of word file is not the contents of one+two, Rather it contents readData value only. But when printing the combined.length i.e resultant length is printing sum of one.length+two.length.
Why above code is not appending contents of two word document?
What am i doing wrong? Please guide me to solve this issue.
Thanks!
It's not possible to combine two proprietary documents via simple bytearray-concatenation. That wouldn't even make any sense. You need to parse the two documents via some library and put them together manually. What you were trying to do is like trying to use two motors inside of one car by attaching a second car to the first one ... does not compute!
Apache offers a library for office documents : https://poi.apache.org/
Replace
fileEditOutPutStream.write(inquiryCor.getLetterWordEditorValue());
with
fileEditOutPutStream.write(inquiryCorrespondence.getLetterWordEditorValue());

Java update data-structure changes to serialized file

I have a hashmap with large number of entry's which is serialized.If i make a small change in hashmap is it required that I overwrite the old file completely or is there an alternative ?
public class HashMapSerial {
public static void main(String[] args) {
HashMap<String,Integer> hash=new HashMap<String, Integer>(100000);
hash.put("hello",1 );
hash.put("world", 2);
//+ (100000 -2) entry's
ObjectOutputStream s=new ObjectOutputStream(new FileOutputStream(new File("hash.out")));
s.writeObject(hash); // write the hash map to file
hash.put("hello",10);
s.writeObject(hash); //rewrite the whole hashmap again
}
}
Since the change is only for the string "hello" and for no other element is it possible to update the serialized file only for the string "hello" instead of rewriting the whole hashmap once again ?
Use DB or simple File IO maintain upto where you have written previously .
AFAIK, you can't do incremental saves with the simple java serialization.
You should instead use another system to store your data (such as a database).
Maybe it's overkill but a NoSQL db (cassandra for instance) would be simpler than trying to create your own system.

Reading an XML File using FileInputStream (for Java)?

For my project I have to serialize and deserialize a random tree using Java and XStream. My teacher made the Tree/RandomTree algorithms, so I don't have to worry about that. What I don't know how to do is this: I am using FileInputStream to read/write the xml file that I serialized and deserialized, but when I deserialize, I do not know the method used to read the file. After I read the file I should be able to convert it from XML and then print it out as a string. Here's what I have so far. (I imported everything correctly, just didn't add it to my code segment).
FileInputStream fin;
try
{
// Open an input stream
fin = new FileInputStream ("/Users/Pat/programs/randomtree.xml");
//I don't know what to put below this, to read FileInpuStream object fin
String dexml = (String)xstream.fromXML(fin);
System.out.println(dexml);
// Close our input stream
fin.close();
System.out.println(dexml);
// Close our input stream
fin.close();
}
// Catches any error conditions
catch (IOException e)
{
System.err.println ("Unable to read from file");
System.exit(-1);
}
Edit: I figured it out; I don't think I have to print it as a string, I just needed to make a benchmarking framework to time it and such, but thanks again!
The xstream.fromXML() method will do the reading from the input stream for you. I think the problem is that you are casting the return value from xstream.fromXML(fin) into a String when it should be cast to the type of object you originally serialized (RandomTree I assume). So the code would look like this:
RandomTree tree = (RandomTree)xstream.fromXML(fin);
EDIT: after clarification in comments, the author's goal is to first read into a String so the XML contents can be printed before deserialization. With that goal in mind, I recommend taking a look at the IOUtils library mentioned in this thread
From what I understand from http://x-stream.github.io/tutorial.html (I've never worked with XStream before), you need to define your types first. Casting to String is definitely wrong, you probably want a customized type (depending on what's inside your random XML), then you need to map the XML tags to your members:
e.g.
xstream.alias("person", Person.class);
xstream.alias("phonenumber", PhoneNumber.class);
meaning that it maps the "person" tag inside your XML to your Person class.
To derserialize, you can do:
RandomTree myRandomTree = (RandomTree)xstream.fromXML( xml );
Also, you are closing your stream twice, and you probably want to do it in a finally block :)
edit: Having read your comment above...
Your task involves two steps:
Deserialization
Serialization
In order to serialize your object, you must deserialize it first from your input file.
To output your Object as String, simply do
String xml = xstream.toXML( myRandomTree );

Categories