I am using the write() method in order to write in a file of the external storage. This method only accepts byte[] as an input. I have tried passing a String and I get an error message ("The method write(int) in the type FileOutputStream is not applicable for the arguments String"). If I pass an int, I don't get error but in the file nothing is written. The value I get from calling getNumSentPackets() is an int and I need to convert it to byte[]. I have been looking at other questions already answered here and I have tried the ByteBuffer option but the result I get in the file is not what I want, this means, I don't get the number of sent packets. Can anybody help me, please?
This is my code:
public void createFile(String name) {
try {
String filename = name;
File myFile = new File(Environment.getExternalStorageDirectory(), filename);
if (!myFile.exists())
myFile.createNewFile();
String title = "FLOODING RESULTS FILE\n\n";
String sent = "Number of sent packets\n";
FileOutputStream fos;
byte[] data = title.getBytes();
byte[] intSent = sent.getBytes();
int numSent = mSender.getNumSentPackets();
byte[] numSentBytes = ByteBuffer.allocate(10).putInt(numSent).array();
try{
fos = new FileOutputStream(myFile);
fos.write(data);
fos.write(intSent);
fos.write(numSentBytes);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static int getNumSentPackets() {
return nSentPackets;
}
The expected output file would be as follows:
FLOODING RESULTS FILE
Number of sent packets 200
200 is only an example, meaning with this that I would like to see there a number which would correspond to the total number of sent packets.
Thank you in advance.
As I am a lazy developer, I like to use the existing facilities in my languages of choice, for example, for java, a PrintWriter.
public void createFile(String filename) {
try {
File myFile = new File(Environment.getExternalStorageDirectory(), filename);
PrintWriter out = new PrintWriter(myFile); // this will create the file if necessary
out.println("FLOODING RESULTS FILE");
out.println();
out.print("Number of sent packets ");
out.println(mSender.getNumSentPackets());
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
This is much easier to read and maintain than your current approach, and looks more idiomatic.
ByteBuffer.allocate(capacity).putInt(yourInt).array();
The text representation of "200" requires you to write 3 characters. All files are just a bunch of bytes in the end so there needs to be a mapping from character to some byte value. Assuming ASCII(*) the data to write into the file would be
// '2','0','0'
byte[] textVersion = { 50, 48, 48 }
int on the other hand is a 32bit numeric value, i.e. has 4 bytes and 200 is equivalent to
byte[] intVersion = { 0, 0, 0, 200 }
When using a ByteBuffer, you'll get this. If you write that into a file and a text viewer tries to display that it would display something like ◻◻◻Č if you're lucky. A 0 is actually a non printable control character and therefore often either skipped when printing or replaced with strange looking character like boxes. The 200 would be equivalent to Č in Windows-CP1250. It has no meaning on it's own when interpreted as UTF8 - it's the start of a 2 byte sequence and so the next 2 byte are required to determine which character to display.
You could have used
String.valueOf(200).getBytes( /* you should specify which encoding to use here */ );
which will create the "200" string first, then return you the required bytes for those 3 characters.
You should however use Java's character based IO facility: The numerous (and confusing) Reader & Writer implementations. They all(*^2) wrap an InputStream or OutputStream in the end and do the text to byte conversion for you.
PrintWriter is probably the most convenient to use but not without flaw: https://stackoverflow.com/a/15803472/995891
FileWriter should be avoided because you can't specify the encoding
The longer alternative route would be
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(file), encoding));
writer.write("Hello ");
writer.write(String.valueOf(200));
writer.newLine();
(*) most encodings are ASCII compatible for the first 127 characters which basically covers normal english text.
(*^2) nothing forces a Writer to output the characters into a stream, e.g. StringWriter. But they are used mostly that way.
Related
I currently work on an app where I use the phone camera and open CV to process the frames. Now I thought it would be cool to be able to send the frames to another Android client. I thought frame by frame with steamer could work, but don't know how to setup the host and if it's not efficient. Any suggestions?
If you just want to send each frame as a raw set of data you can use sockets.
This code below is old now but it worked fine when last tested - it sends an entire video but you can use the same to send whatever file you want:
//Send the video file to helper over a Socket connection so he helper can compress the video file
Socket helperSocket = null;
try {
Log.d("VideoChunkDistributeTask doInBackground","connecting to: " + helperIPAddress + ":" + helperPort);
helperSocket = new Socket(helperIPAddress, helperPort);
BufferedOutputStream helperSocketBOS = new BufferedOutputStream(helperSocket.getOutputStream());
byte[] buffer = new byte[4096];
//Write the video chunk to the output stream
//Open the file
File videoChunkFile = new File(videoChunkFileName);
BufferedInputStream chunkFileIS = new BufferedInputStream(new FileInputStream(videoChunkFile));
//First send a long with the file length - wrap the BufferedOutputStream in a DataOuputStream to
//allow us send a long directly
DataOutputStream helperSocketDOS = new DataOutputStream(
new BufferedOutputStream(helperSocket.getOutputStream()));
long chunkLength = videoChunkFile.length();
helperSocketDOS.writeLong(chunkLength);
Log.d("VideoChunkDistributeTask doInBackground","chunkLength: " + chunkLength);
//Now loop through the video chunk file sending it to the helper via the socket - note this will simply
//do nothing if the file is empty
int readCount = 0;
int totalReadCount = 0;
while(totalReadCount < chunkLength) {
//write the buffer to the output stream of the socket
readCount = chunkFileIS.read(buffer);
helperSocketDOS.write(buffer, 0, readCount);
totalReadCount += readCount;
}
Log.d("VideoChunkDistributeTask doInBackground","file sent");
chunkFileIS.close();
helperSocketDOS.flush();
} catch (UnknownHostException e) {
Log.d("VideoChunkDistributeTask doInBackground","unknown host");
e.printStackTrace();
return null;
} catch (IOException e) {
Log.d("VideoChunkDistributeTask doInBackground","IO exceptiont");
e.printStackTrace();
return null;
}
The full source code is at: https://github.com/mickod/ColabAndroid/tree/master/src/com/amodtech/colabandroid
You may also find there are more up to date socket libraries available which might be better for you to use, but the general principles should be similar.
If you want to stream your video so that the other app can play it like a regular video it streams from the web, then you would want to set up a web server on the 'sending' device. At this point it might be easier to send it to a server and stream from there instead.
I am trying to create a chat application between Android and a Windows 10 device.
I have successfully sent text from Android using DataOutputStream and read it in Windows 10 using a data reader class.
My problem is Android is not able to recognize the text from Windows. It displays the result of the datainputstream.available() function but the application hangs in case I use the readString() or the readbyte() function.
Code in Android for receiving:
DataInputStream dIn = new DataInputStream(clientSocket.getInputStream());
if(dIn.available()>0)
{
int length = dIn.readInt(); // app hangs in here
byte[] byteReceived = new byte[length];
dIn.readFully(byteReceived, 0 , length); // sometimes app hangs here
String textReceived = new String(byteReceived);
text.setText(Client Says: "+ textReceived + "\n");//
}
Data sent from Windows through datawriter:
DataWriter writer = new DataWriter(socket.OutputStream))
{
writer.UnicodeEncoding=windows.Storage.Streams.UnicodeEncoding.Utf8;
writer.ByteOrder = windows.Storage.Streams.ByteOrder.LittleEndian;
uint size =writer.MeasureString(message);
writer.WriteUint32(size);
writer.WriteString(message);
try
{
await writer.StoreAsync();
}
catch (Exception exception)
{
switch (SocketError.GetStatus(exception.HResult))
{
case SocketErrorStatus.HostNotFound:
// Handle HostNotFound Error
throw;
default:
throw;
}
}
await writer.FlushAsync();
writer.DetachStream();
}
What is the issue here?
Your dIn.readFully expects bytes and not String. Moreover, it expects the exact number of bytes, as length variable. You need to create bytes from String on the windows size and send the length of byte array as Int in first transaction. Then you need to transfer this byte array unchanged in second transaction. Try it.
I Am trying to load a class as a byte array so I could send it over the network and execute it remotely via Reflection. This Class (Bubble in this case) is in the same package. The thing is that I can't get the resource using the getResourceAsStream(classpath) method.
The .getResourceAsStream(classpath) is always returning null. I've tested this code in a Java project and worked properly. I think the problem is the resource path, does Android load a .class file?
private void doSomething() {
Bubble b = new Bubble();
try {
//Try to retrieve the class byte array
byte[] classBytes = getBytes(b.getClass());
} catch (IOException e) {
e.printStackTrace(System.err);
}
...
}
private byte[] getBytes(Class c) throws IOException{
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte b[] = new byte[1024];
String classpath = c.getCanonicalName().replace('.', File.pathSeparatorChar) + ".class";
//classpath is now, for example, com:myproject:Bubble.class
InputStream in = c.getClassLoader().getResourceAsStream(classpath);
int load;
while((load=in.read(b))>0){
out.write(b,0,load);
}
byte[] _r = out.toByteArray();
out.close();
in.close();
return _r;
}
Android uses dex file format for classes, and the best way would be to not send zipped (jarred) classes.dex, which contains all classes you need.
I'm trying to transfer about a megabyte of arbitrary data at a time from one android phone to another. Currently, I write the size, a command code and the data to a DataOutputStream around a BufferedOutputStream, around the OutputStream returned from bluetoothSocketInstance.getOutputStream().
The receiving phone reads the size and command code and then reads from the input stream until it has gotten all the data it is expecting. This works for short strings, but for larger files not all the data is transferred. Running the app in the debugger shows that the write returns without any exceptions and the read reads a fraction of the bytes expected and then blocks indefinitely. It also does not throw any exceptions.
Is there a buffer somewhere that is filling up? Is there something else I need to do to ensure that all the data gets transferred?
My code for the sender and receiver are below:
Sender:
try {
DataOutputStream d = new DataOutputStream(new BufferedOutputStream(mmOutStream,buffer.length+8));
//int b= buffer.length;
d.writeInt(buffer.length);
d.writeInt(command);
d.write(buffer);
d.flush();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
Receiver:
try {
// Read from the InputStream
int messageSize= inStream.readInt();
int messageCode = inStream.readInt();
bytes=0;
buffer =new byte[messageSize];
while(bytes < messageSize)
{
bytes += inStream.read(buffer,bytes,messageSize - bytes);
}
message = bytes;
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
After some more testing on my end, I changed my sending code to look like this:
for(int i=0; i<buffer.length;i+=BIG_NUM)
{
int b = ((i+BIG_NUM) < buffer.length) ? BIG_NUM: buffer.length - i;
d.write(buffer,i,b);
d.flush();
}
The files now get sent. Does anyone have an idea why? Does the call to flush() block until the data has actually been transferred? Is there any documentation about the size of the send and receive buffers that would help me to decide how large I can safely make BIG_NUM?
I have similar problem, when sending file there are some parts missing. I try BufferedOutputStream but problem still exist.
Finally i find simple solution:
You don't need to send buffer length, just split sending buffer to byte array (for example [8192]) and on receive side make sure that this buffer is much bigger about 4 or 8 times than sending buffer. This worked for me and file is sent completed.
The problem is that I’m using the write method of the FileOutputStream class. The docs I read said this outputs a byte to the file. I cannot find a read methes in the FileOutputStream class.
But there is a read method ikn the InputStreamReader. The problem, is that the documentation I read said this class read function returns a char, by converting the bytes to a char. Will this change the data. How should I read the data back in.
code that saves the file and seems to work
boolean Save()
{
String FILENAME = "hello_file";
String string = "hello world!";
cDate mAppoitments[];
try {
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE );
int i;
mAppoitments=cDates.GetUpperDates();
for(i=0;i<cDates.getMaxAmount();i++)
{
i=mAppoitments[i].getMonth();
fos.write( i );
i=mAppoitments[i].getDay();
fos.write( i );
i=mAppoitments[i].getYear()-1900;
fos.write( i );
}
mAppoitments=cDates.GetLowerDates();
for(i=0;i<cDates.getMaxAmount();i++)
{
i=mAppoitments[i].getMonth();
fos.write( i );
i=mAppoitments[i].getDay();
fos.write( i );
i=mAppoitments[i].getYear()-1900;
fos.write( i );
}
fos.close();
}
// just catch all exceptions and return false
catch (Throwable t) {
return false;
}
return true;
}
Just open the file as a stream:
// open the file for reading
InputStream instream = openFileInput(FILENAME);
// prepare the file for reading
InputStreamReader inputreader = new InputStreamReader(instream);
BufferedReader buffreader = new BufferedReader(inputreader);
Than you can read it line by line
The rule I have is to use the same type of stream for reading and writing. So if you opened a file for writing using openFileOutput, use openFileInput to open the input stream for reading. since the method write(int) writes one byte to the file, you may safely use the method read() to read each byte and assign it to the variable.
BUT, there is a big problem in your loops - you modify i inside the loop, unrelated to the indexing:
i=mAppoitments[i].getMonth(); // now i might be assigned with 12
fos.write( i ); // you write 12
i=mAppoitments[i].getDay(); // now you look for mAppoitments[12].getDay()
....
Use a different variable to write those value to the file, don't modify i inside the loop. For example:
for(i=0;i<cDates.getMaxAmount();i++)
{
int j;
j=mAppoitments[i].getMonth();
fos.write( j );
j=mAppoitments[i].getDay();
fos.write( j );
j=mAppoitments[i].getYear()-1900;
fos.write( j );
}
If it's more comfortable for you, you can wrap the output stream in a PrinterWriter, and you can wrap the input steam reader in a BufferedReader. Then, you could write and read Strings.
I think you'll have some issues with using i for an iterator and as your variable for storing what you're writing.