I have a file containing java objects, wrote with this code:
from(somewhere).process(new Processor() {
#Override
public void process(final Exchange exchange) {
...
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(myObject);
exchange.getOut().setBody(bos.toByteArray());
}
}).to("file://pathFile");
And now, I want read them fastly. I don't know how can I do that, something like the following code I gess.
from("file://pathFile").convertBodyTo(String.class)
.split(body().tokenize("???")) // How can I tokenize my file ?
.streaming().threads(2)
.process(new Processor() {
#Override
public void process(final Exchange exchange) {
String filePath = (String) exchange.getIn().getHeader(Exchange.FILE_PATH);
File file = new File(filePath);
MyObject myObject = null;
try {
FileInputStream fis = new FileInputStream(file);
InputStream buffer = new BufferedInputStream(fis);
ObjectInput input = new ObjectInputStream(buffer);
Object obj = null;
while ((obj = input.readObject()) != null) {
// Do something
myObject = obj;
}
} catch (Exception e) {
...
} finally {
...
}
exchange.getIn().setBody(myObject);
}
}).to(somewhere);
EDIT: I edit my way to read object. There is still a problem with that code, we can't append to an ObjectOutputStream. That will corrupt the stream. There is a solution [here] for this problem. We can only write the stream header one time.
But If I do that, I wont be able to split and read my file with multiple threads. So can I split or access my file on ObjectOutputStream header ?
you just converted it to a String using convertBodyTo(String.class), therefore you have a String in the body rather than an InputStream....
Related
I want to write a class object to the string and then again create an object from it.
I searched on the net but all I found is to write an object to file however I want to write in the string, not on file.
Below is the example of writing to file similarly I want to write in String or similar Object and not in the file.
some_class implements serializable {
...
}
FileOutputStream f = new FileOutputStream(new File("myObjects.txt"));
ObjectOutputStream o = new ObjectOutputStream(f);
// Write objects to file
o.writeObject(object1);
o.close();
f.close();
FileInputStream fi = new FileInputStream(new File("myObjects.txt"));
ObjectInputStream oi = new ObjectInputStream(fi);
// Read objects
some_class object2 = (some_class) oi.readObject();
oi.close();
fi.close();
Please help with the same.
This would be one way:
try
{
// To String
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos);
os.writeObject(object1);
String serializedObject1 = bos.toString();
os.close();
// To Object
ByteArrayInputStream bis = new ByteArrayInputStream(serializedObject1.getBytes());
ObjectInputStream oInputStream = new ObjectInputStream(bis);
YourObject restoredObject1 = (YourObject) oInputStream.readObject();
oInputStream.close();
} catch(Exception ex) {
ex.printStackTrace();
}
I would prefer the Base64 way though.
This would be an example of encoding:
private static String serializableToString( Serializable o ) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
And this is an example of decoding:
private static Object objectFromString(String s) throws IOException, ClassNotFoundException
{
byte [] data = Base64.getDecoder().decode(s);
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data));
Object o = ois.readObject();
ois.close();
return o;
}
the best way to serialize an object to String and vice versa you should convert the object into JSON String and encode into base64. and to get object decode base64 and convert to object using GSON (opensource google provide java library)
class foo{ String name, email;
//setter getter
}
convert Object to base64 JSON
public static String convertToJson(Object o){
String result=new Gson().toJson(o);
return Base64.getEncoder().encodeToString(result);
}
//read base64
public static <T> T convertJsonToObject(String base64Object,Class<T> classOfT){
Gson gson = new Gson();
return gson.fromJson(new InputStreamReader(new ByteArrayInputStream(Base64.getDecoder().decode(base64Object))),classOfT);
}
public static void main(String[] args) {
foo obj=new foo("jhon","jhon#gamil.com");
String json=convertToJson(foo);
System.out.println(json);
foo obj_fromJson=convertJsonToObject(json,foo.class);
System.out.println(obj_fromJson.getName());
}
I'm trying to read and write objects into a file. Reading the output into a new object works, but every value is null.
Here's the code:
public void read() throws Exception
{
try
{
FileInputStream fIn = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fIn);
Object obj = in.readObject();
System.out.println(obj);
public void save() throws Exception
{
FileOutputStream fOut = new FileOutputStream(file.toString());
ObjectOutputStream out = new ObjectOutputStream(fOut);
out.writeObject(this);
out.flush();
out.close();
}
Here is the file output: (image of output)
I'd like to receive the values I previously wrote to the file in the new object created, however all I get is null for all values.
Edit: since people are asking for the entire class, and I have no idea what code could be causing what, here's the entire UserFile class: https://pastebin.com/Gr1tcGsg
I have ran that code and it works which means you most likely read before you write or you got an exception such as InvalidClassException: no valid constructor which would make sense in your case.
The code I ran:
public class SavedObject implements Serializable
{
public static void main(String[] args) throws IOException, ClassNotFoundException
{
new SavedObject();
}
private final int random;
private SavedObject() throws IOException, ClassNotFoundException
{
random = ThreadLocalRandom.current().nextInt();
File file = new File("Object.txt");
save(file);
read(file);
}
private void save(File file) throws IOException
{
FileOutputStream fileOutput = new FileOutputStream(file);
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(this);
objectOutput.close();
fileOutput.close();
System.out.println(this);
}
private void read(File file) throws IOException, ClassNotFoundException
{
FileInputStream fileInput = new FileInputStream(file);
ObjectInputStream objectInput = new ObjectInputStream(fileInput);
Object obj = objectInput.readObject();
System.out.println(obj);
objectInput.close();
fileInput.close();
}
public String toString()
{
return "SavedObject(Random: " + random + ")";
}
}
Which prints:
SavedObject(Random: -2145716528)
SavedObject(Random: -2145716528)
Also a few tips for you:
Don't have a try-catch if you throws
Have more readable variable names
Send more code in your next question
ObjectOutputStream is not recommended, if you can, you should write the values as they are
Don't use throws "Exception" instead use throws "
Put the file in instead of file.toString()
I found the problem, it was that in my constructor I wasn't correctly applying the retrieved info from the file. Thanks for everyone's help.
I have a problem that I have not been able to solve and it does not occur to me that it could be.
I have a class to which I am passing an InputStream from the main method, the problem is that when transforming the InputString to String with the class IOUtils.toString of AWS, or with the IOUtils of commons-io, they return
an empty String
No matter what the problem may be, since inside the main class, it works correctly and returns the String it should, but when I use it inside the other class (without having done anything), it returns the empty String to me.
these are my classes:
public class Main {
public static void main(String [] args) throws IOException {
InputStream inputStream = new ByteArrayInputStream("{\"name\":\"Camilo\",\"functionName\":\"hello\"}".getBytes());
OutputStream outputStream = new ByteArrayOutputStream();
LambdaExecutor lambdaExecutor = new LambdaExecutor();
String test = IOUtils.toString(inputStream); //this test variable have "{\"name\":\"Camilo\",\"functionName\":\"hello\"}"
lambdaExecutor.handleRequest(inputStream,outputStream);
}
}
and this:
public class LambdaExecutor{
private FrontController frontController;
public LambdaExecutor(){
this.frontController = new FrontController();
}
public void handleRequest(InputStream inputStream, OutputStream outputStream) throws IOException {
//Service service = frontController.findService(inputStream);
String test = IOUtils.toString(inputStream); //this test variable have "" <-empty String
System.exit(0);
//service.execute(inputStream, outputStream, context);
}
}
I used the debug tool, and the InputStream object is the same in both classes
By the time that you've passed the stream into handleRequest(), you've already consumed the stream:
public static void main(String [] args) throws IOException {
InputStream inputStream = new ByteArrayInputStream("{\"name\":\"Camilo\",\"functionName\":\"hello\"}".getBytes());
OutputStream outputStream = new ByteArrayOutputStream();
LambdaExecutor lambdaExecutor = new LambdaExecutor();
String test = IOUtils.toString(inputStream); //this consumes the stream, and nothing more can be read from it
lambdaExecutor.handleRequest(inputStream,outputStream);
}
When you took that out, the method worked as, as you said in the comments.
If you want the data to be re-useable, you'll have to use the reset() method if you want the same data again, or close and re-open the stream to re-use the object with different data.
// have your data
byte[] data = "{\"name\":\"Camilo\",\"functionName\":\"hello\"}".getBytes();
// open the stream
InputStream inputStream = new ByteArrayInputStream(data);
...
// do something with the inputStream, and reset if you need the same data again
if(inputStream.markSupported()) {
inputStream.reset();
} else {
inputStream.close();
inputStream = new ByteArrayInputStream(data);
}
...
// close the stream after use
inputStream.close();
Always close the stream after you use it, or use a try block to take advantage of AutoCloseable; you can do the same with the output stream:
try (InputStream inputStream = new ByteArrayInputStream(data);
OutputStream outputStream = new ByteArrayOutputStream()) {
lambdaExecutor.handleRequest(inputStream, outputStream);
} // auto-closed the streams
The reason you can't is because you can only read from a stream once.
To be able to read twice, you must call the reset() method for it to return to the beginning. After reading, call reset() and you can read it again!
Some sources don't support resetting it so you would actually have to create the stream again. To check if the source supports it, use the markSupported() method of the stream!
Not able to read object and data from the file at the same time in java
m able to write the object into the file but not able to fetch all the objects only first object is fetched and also data after object is not able to retrieve
import java.io.*;
import java.util.*;
class writeobj implements Serializable
{
public String name;
public long size;
}
class FileLists
{
public static void main(String[] args) throws Exception
{
try{
File folder = new File("/home/shubham/Desktop/packer/dem");
File[] files = folder.listFiles();
FileOutputStream fobj = new FileOutputStream("myfile.ser");
ObjectOutputStream oobj = new ObjectOutputStream(fobj);
int ch;
for (File file : files)
{
if (file.isFile())
{
writeobj obj = new writeobj();
obj.name = file.getName();
obj.size = file.length();
oobj.writeObject(obj);
String str = file.getAbsolutePath();
FileInputStream fre =new FileInputStream(str);
System.out.println(file.getName()+"-"+file.length()+"-"+str);
//FileReader f = new FileReader(obj.name);
byte[] buffer = new byte[1024];
while((ch = fre.read(buffer))!=-1){
//System.out.println((char)ch);
fobj.write(buffer,0,ch);
}
//Fread = null;
fre.close();
obj = null;
}
}
}
catch(Exception e)
{
System.out.println(e);
}
}
}
reading from this file it only read first object and create that file but after that not data not object are able to read from the myfile.ser
import java.io.*;
import java.util.*;
class writeobj implements Serializable
{
public String name;
public long size;
}
class FileLists
{
public static void main(String[] args)
{
int ch;
//File folder = new File("/home/shubham/Desktop/packer/dem/hello/demo");
try
{
FileInputStream fobj = new FileInputStream("myfile.ser");
//BufferedInputStream br = new BufferedInputStream(fobj);
ObjectInputStream ois = new ObjectInputStream(fobj);
writeobj e;
while( (e = (writeobj)ois.readObject()) != null)
{
FileWriter f = new FileWriter(e.name);
System.out.println(e.name+"name :"+e.size);
while((ch=ois.read())!= -1){
System.out.println("as");
}
}
}
catch(Exception ef){
System.out.println();
ef.printStackTrace();
}
}
}
Stack Traces:
java.io.StreamCorruptedException: invalid type code: 69 at
java.base/java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(ObjectInputStream.java:2937)
at
java.base/java.io.ObjectInputStream$BlockDataInputStream.refill(ObjectInputStream.java:2971)
at
java.base/java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:3043)
at
java.base/java.io.ObjectInputStream.read(ObjectInputStream.java:906)
at FileLists.main(createnewfile.java:33)
The problem likely lies here:
while((ch=ois.read())!= -1){
System.out.println("as");
}
You are writing the 'writeobj' class, followed by the file bytes, and then repeat.
So, your saved file will, hopefully, look like:
writeobj - written with ObjectOutputStream
file bytes - written directly to the FileOutputStream
writeobj - written with ObjectOutputStream
file bytes - written directly to the FileOutputStream
But, when you are reading, you read one writeobj object, and then attempt to read another object from the ObjectInputStream.
For this to work, you would have to:
Read the writeobj from the ObjectInputStream
Read the exact number of file bytes directly from the FileInputStream
Read the next writeobj from the ObjectInputStream
etc...
I'm trying to write a client-server application in Java with an XML-based protocol.
But I have a great problem!
See this part of client code:
InputStream incoming = skt.getInputStream(); //I get Stream from Socket.
OutputStream out = skt.getOutputStream();
[...]
XMLSerializer serializer = new XMLSerializer();
//This create an XML document.
tosend = WUTPClientWriter.createMessage100(projectid, cpuclock, cpunumber);
serializer.setOutputByteStream(out);
serializer.serialize(tosend);
At this point server fall in deadlock. It wait for EOF but I can't send it because if I use
out.close();
or
skt.shutdownOutput();
I close the Socket and I must keep this connection alive.
I can't send '\0' becouse I get Parse Error in the server.
How can I do it? Can I "close" the output stream without closing the socket?
RESOLVED
I've created new class XMLStreamOutput and XMLStreamInput with advanced Stream gesture.
I've resolved with this four class:
1)
public class XMLOutputStream extends ByteArrayOutputStream {
private DataOutputStream outchannel;
public XMLOutputStream(OutputStream outchannel) {
super();
this.outchannel = new DataOutputStream(outchannel);
}
public void send() throws IOException {
byte[] data = toByteArray();
outchannel.writeInt(data.length);
outchannel.write(data);
reset();
}
}
2)
public class XMLSender {
public static void send(Document tosend, OutputStream channel) throws TransformerConfigurationException, IOException {
XMLOutputStream out = new XMLOutputStream(channel);
StreamResult sr = new StreamResult(out);
DOMSource ds = new DOMSource(tosend);
Transformer tf = TransformerFactory.newInstance().newTransformer();
try {
tf.transform(ds, sr);
} catch (TransformerException ex) {
Logger.getLogger(XMLSender.class.getName()).log(Level.SEVERE, null, ex);
}
out.send();
}
}
3)
public class XMLInputStream extends ByteArrayInputStream {
private DataInputStream inchannel;
public XMLInputStream(InputStream inchannel) {
super(new byte[2]);
this.inchannel = new DataInputStream(inchannel);
}
public void recive() throws IOException {
int i = inchannel.readInt();
byte[] data = new byte[i];
inchannel.read(data, 0, i);
this.buf = data;
this.count = i;
this.mark = 0;
this.pos = 0;
}
}
4)
public class XMLReceiver {
public static Document receive(InputStream channel) throws ParserConfigurationException, TransformerConfigurationException, IOException, SAXException {
DocumentBuilderFactory docBuilderFact = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFact.newDocumentBuilder();
Document request = null;
XMLInputStream xmlin = new XMLInputStream(channel);
xmlin.recive();
request = docBuilder.parse(xmlin);
return request;
}
}
You don't want to close the socket's OutputStream, because the socket only has one OutputStream.
It looks like you just need to flush your OutputStream after writing to it.
out.flush();
EDIT: Thanks for the extra info. If you're reading the socket like this, receiver needs to know when you're done writing. An InputStream only knows you're done writing if you close the socket.
But since you have already stated you can't close the socket, you need another way of telling the receiving side that you're done. You either need to use a special type of stream which knows about the data being sent, or you need to set up a contract for writing/reading the appropriate amount of data.
It would probably be easiest to send the data as an Object (using ObjectOutputStream/ObjectInputStream--maybe you don't even need to convert to XML).
If you don't want the overhead associated with Object streams, the simple solution is to compute the length of the data being sent, and send that number just prior to sending the actual data. In this case, you can use a DataOutputStream/DataInputStream. Send the number of bytes to read, followed by the data. On the receiving side, read the number, then read the given number of bytes into a temporary variable and feed that to DocumentBuilder.parse(InputStream).
On the sending end, you would do this:
DataOutputStream out = new DataOutputStream(s.getOutputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLSerializer serializer = new XMLSerializer();
serializer.setOutputByteStream(baos);
tosend = WUTPClientWriter.createMessage100(projectid, cpuclock, cpunumber);
serializer.serialize(tosend);
out.writeInt(baos.size());
out.write(baos.toByteArray());
out.flush();
Then on the receiving end, you do something like the following:
DataInputStream in = new DataInputStream(s.getInputStream());
int len = in.readInt();
byte[] xml = new byte[len];
in.read(xml, 0, len);
Document doc = builder.parse(new ByteArrayInputStream(xml));