Progress Bar time calculation + java - java

I am transferring file from client to server. I dont know the amount of time it will take to transfer. But my UI will simple remain the same without any intimation to user. I need to keep a progress bar in such a way it should be progress till file is uploaded. How can i acheive this.
I am abit aware of this scenario in .net. but how can we do it in java?

trashgod's answer is correct for actions that are truly 'indeterminate'. Why do you think that your file transfer fits into this category? Haven't you ever downloaded a file on the internet with some sort of progress bar associated with it? Can you imagine not having that?
See the example below that was provided among the answers to How do I use JProgressBar to display file copy progress?
public OutputStream loadFile(URL remoteFile, JProgressBar progress) throws IOException
{
URLConnection connection = remoteFile.openConnection(); //connect to remote file
InputStream inputStream = connection.getInputStream(); //get stream to read file
int length = connection.getContentLength(); //find out how long the file is, any good webserver should provide this info
int current = 0;
progress.setMaximum(length); //we're going to get this many bytes
progress.setValue(0); //we've gotten 0 bytes so far
ByteArrayOutputStream out = new ByteArrayOutputStream(); //create our output steam to build the file here
byte[] buffer = new byte[1024];
int bytesRead = 0;
while((bytesRead = inputStream.read(buffer)) != -1) //keep filling the buffer until we get to the end of the file
{
out.write(buffer, current, bytesRead); //write the buffer to the file offset = current, length = bytesRead
current += bytesRead; //we've progressed a little so update current
progress.setValue(current); //tell progress how far we are
}
inputStream.close(); //close our stream
return out;
}

As shown in How to Use Progress Bars, you can specify indeterminate mode until you either have enough data to gauge progress or the download concludes. The exact implementation depends on how the transfer takes place. Ideally, the sender provides the length first, but it may also be possible to calculate the rate dynamically as data accumulates.

Related

openPrefetchingReadChannel is not working in Google Cloud Storage Client API

I am trying to fetch object from bucket using openPrefetchingReadChannel GCSInputChannel. As Google developer tutorial says:
GcsInputChannel readChannel = gcsService.openPrefetchingReadChannel(fileName, 0, 1024 * 1024);
Prefetching provides is a major performance advantage for most applications, because it
allows processing part of the file while more data is being downloaded in the background
in parallel.The third parameter is the size of the prefetch buffer, set in the example
to 1 megabyte.
Well this is not happening for me. Please have a look at my snippet:
GcsInputChannel readChannel = gcsService.openPrefetchingReadChannel(fileName, 0, 1024);
copy(Channels.newInputStream(readChannel), resp.getOutputStream());
private void copy(InputStream input, OutputStream output) throws IOException {
try {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = input.read(buffer);
while (bytesRead != -1) {
output.write(buffer, 0, bytesRead);
bytesRead = input.read(buffer);
}
} finally {
input.close();
output.close();
}
}
Ref: https://code.google.com/p/appengine-gcs-client/source/browse/trunk/java/example/src/com/google/appengine/demos/GcsExampleServlet.java
Above code should deliver 1KB of data from uploaded object but it is returning the whole data of object i.e. 8.4KB. Please look at the screenshot:
I am not sure what is happening. Need your help guys
The third argument for openPrefetchingReadChannel is not the max size to read (or limit).
Is the the internal buffer size for prefetching. In your case you may want to track how much
you read and keep writing until reached the desired limit

Java SequenceInputStream

I try to send multiple Files from my Server (NanoHttpd) to my Client (Apache DefaultHttpClient).
My approach is to send multiple files via one Response of NanoHttpd.
For this purpose i wanted to use SequenceInputStream.
I am trying to concatenate multiple Files, send them via the Response (InputStream) and write every File again in a seperate File with my Client.
On the Serverside i call this:
List<InputStream> data = new ArrayList<InputStream>(o_file_path.size());
for (String file_name : files)
{
File file = new File(file_name);
data.add(new FileInputStream(file));
}
InputStream is = new SequenceInputStream(Collections.enumeration(data));
return new NanoHTTPD.Response(HTTP_OK, "application/octet-stream", is);
Now my Question is how to receive and split the Files correctly.
I have tried it this way on my client, but it does not work:
int read = 0;
int remaining = 0;
byte[] bytes = new byte[buffer];
// Read till the end of the Stream
while ( (read != -1) && (counter < files.size()))
{
// Create a .o file for the current file
read = 0;
remaining = is.available();
// Should open each Stream
while (remaining > 0)
{
read = is.read(bytes);
remaining = remaining - read;
os.write(bytes, 0, read);
}
os.flush();
os.close();
}
This way I want to go over all Stream (untill read == 1, or i know there is no file anymore), and read any stream into a file.
I clearly seem to understand something groundbreaking wrong, since is.available() always is 0.
Could anyone please tell me how to read properly from this SequencedInputStream, or how to solve my Problem.
Thanks in advance.
It won't work this way. SequenceInputStream will merge all input streams in one solid byte stream. There will be no separators or EOFs. I suggest to abandon the idea and look for a different approach.

Get size of uncompressed gzip file while size of compressed file is available from server

I am using GZIPInputStream to download PDF file. I want to show the download progress of the file on a UI button. But, I am not getting the actual size of the file, what I am getting is compressed size due to which I am unable to show the correct download progress. This download progress is exceeding 100 as the actual file size is greater than the compressed size of file.
Header content of file from server: Following info I receive from server, from which I am using content-length which is giving compressed file size.
1.Connection
2.Content-Encoding
3.Content-length
4.Content-Type
5.Keep-Alive
6.Server
7.Date
Here is my code. Is there any way to get original size of file?
long fileLength = httpResponse.getEntity().getContentLength();//
GZIPInputStream input = new GZIPInputStream(new BufferedInputStream(
httpResponse.getEntity().getContent()));
FileOutputStream output = new FileOutputStream(destinationFilePath);
byte data[] = new byte[1024];
long total = 0;
float percentage = 0;
int count;
currentDownloadingPercentage=0;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
// publishing the progress....
percentage = (float)total/(float)fileLength;
percentage *= 100;
if ((int)percentage > (int)currentDownloadingPercentage) {
currentDownloadingPercentage = percentage;
Bundle resultData = new Bundle();
resultData.putBoolean(DOWNLOAD_FAILED, false);
resultData.putInt(DOWNLOAD_PROGRESS ,(int)percentage);
receiver.send(processID, resultData);
resultData = null;
}
}
You're looking at it the wrong way. You should be counting the compressed bytes that you read and calculating the progress based on those. Instead, you're counting the decompressed bytes and comparing it with the compressed file size. In answer to your question, there's no (reliable) way to determine the size of a gzipped file without decompressing it.
Update: Here's one way you could count the uncompressed bytes coming in. Wrap the raw input stream with a TeeInputStream before wrapping it with the GZIPInputStream. Make the TeeInputStream branch to a CountingOutputStream. Then you'll always have a current count of the compressed bytes that have been downloaded via getByteCount()
This issue discuss result seems not way to avoid HttpURLConnection.getInputStream() automatically returned GZIPInputStream, once you let HttpURLConnection accept gzip compression, you won't calculate download progress accurately, the only one we can do just disable gzip as acceptable encoding :
HttpURLConnection.setRequestProperty("Accept-Encoding", "identity");
Another choice is use AndroidHttpClient, I had tested about this, even we present accept gzip encoding like this :
HttpUriRequest.addHeader("Accept-Encoding", "gzip");
the InputStream instance that return by HttpResponse.getEntity().getContent() will be EofSensorInputStream, an original InputStream is what we wanted, isn't GZIPInputStream, that make us possible to wrap it to GZIPInputStream by myself, we can use TeeInputStream and CountingOutputStream to finish calculating download progress.
HttpResponse response = ...;
HttpEntity entity = response.getEntity();
long fileSize = entity.getContentLength();
InputStream ins = entity.getContent(); // instance of EofSensorInputStream
CountingOutputStream coStrem = new CountingOutputStream(new ByteArrayOutputStream(100));
GZIPInputStream inStrem = new GZIPInputStream(new TeeInputStream(ins, coStrem, true));
byte[] buffer = new byte[6 * 1024]; // 6K buffer
int offset;
while ((offset = inStrem.read(buffer)) != -1) {
tmpFileRaf.write(buffer, 0, offset);
postDownloadProgress(fileSize, coStrem.getByteCount());
}
I think that's all we can do with this problem, I tried pick up android libcore source with my project so we can customize HttpURLConnectionImpl then suppress it return GZIPInputStream, but many errors makes trouble, I discard this effort.
In this post, Jesse Wilson suggested we the best choice client of Android is HttpURLConnection, so I'm looking for how to solve this problem always, I hope I can get a way soon.

Reading several byte[] from DataInputStream

What I need to do is send multiple files using DataStreams. I'm doing this by sending the name of the file, and then the file's bytes. I need to send an undetermined number of files though. Here is the DataOutputStream code.
out.writeUTF(path);
out.write(Files.readAllBytes(file.toPath()));
It does that for each file that needs to be sent. But I don't know how to read it correctly with DataInputStream. This is what I have so far.
while (in.available() != 0) {
String path = in.readUTF();
byte bytes = in.readByte();
}
Obviously it wouldn't work, since it is only reading one byte. But I don't know how to make it read all of the bytes. Since there are several files being sent, available() would only equal 0 when the end of all the files are read, I think. Any help is greatly appreciated.
Something I completely forgot to mention, I want to be able to send a large file without running out of memory, and I don't think this would work. I think I would need to use a buffer, but I don't know what class supports that with files.
Anytime you send variable length messages you need some way to mark the beginning and end of each method.
List<File> files = someListOfFilesYouWantToSend;
out.writeInt(files.size());
for(File file : files){
out.writeUTF(path);
out.writeLong(file.getTotalSpace());
out.write(Files.readAllBytes(file.toPath()));
}
Then to read it you would do something like this
int filesToRead = in.readInt();
for(int i = 0; i < filesToRead; i++){
String path = in.readUTF();
long bytesToRead = in.readLong();
FileOutputSteam fos = new FileOutputStream(path);
byte[] buffer = new byte[1024];
while(bytesToRead > 0){
bytesRead = in.read(buffer,0,bytesToRead > buffer.length ? buffer.length : bytesToRead);
bytesToRead -= bytesRead;
fos.write(buffer);
}
}
That's not the way to do it... Why won't you simply archive all the files you want to send in an archive (like a JAR or ZIP)? On the receiving side you can extract the archive. Java has a built-in JAR implementation (in package java.util.jar) that you can use.

Reading and writing binary file in Java (seeing half of the file being corrupted)

I have some working code in python that I need to convert to Java.
I have read quite a few threads on this forum but could not find an answer. I am reading in a JPG image and converting it into a byte array. I then write this buffer it to a different file. When I compare the written files from both Java and python code, the bytes at the end do not match. Please let me know if you have a suggestion. I need to use the byte array to pack the image into a message that needs to be sent over to a remote server.
Java code (Running on Android)
Reading the file:
File queryImg = new File(ImagePath);
int imageLen = (int)queryImg.length();
byte [] imgData = new byte[imageLen];
FileInputStream fis = new FileInputStream(queryImg);
fis.read(imgData);
Writing the file:
FileOutputStream f = new FileOutputStream(new File("/sdcard/output.raw"));
f.write(imgData);
f.flush();
f.close();
Thanks!
InputStream.read is not guaranteed to read any particular number of bytes and may read less than you asked it to. It returns the actual number read so you can have a loop that keeps track of progress:
public void pump(InputStream in, OutputStream out, int size) {
byte[] buffer = new byte[4096]; // Or whatever constant you feel like using
int done = 0;
while (done < size) {
int read = in.read(buffer);
if (read == -1) {
throw new IOException("Something went horribly wrong");
}
out.write(buffer, 0, read);
done += read;
}
// Maybe put cleanup code in here if you like, e.g. in.close, out.flush, out.close
}
I believe Apache Commons IO has classes for doing this kind of stuff so you don't need to write it yourself.
Your file length might be more than int can hold and than you end up having wrong array length, hence not reading entire file into the buffer.

Categories