I'm trying to make a progress bar or something like that in my program that is sending files to a server. I've this
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(file.getName());
FileInputStream fis = new FileInputStream(file);
byte [] buffer = new byte[Server.BUFFER_SIZE];
Integer bytesRead = 0;
jj = size-bytesRead;
int i = 0;
while ((bytesRead = fis.read(buffer)) > 0) {
oos.writeObject(bytesRead);
jButton3.doClick();
oos.writeObject(Arrays.copyOf(buffer, buffer.length));
}
oos.close();
ois.close();
And this is Button3
temp = temp - 100;
jLabel3.setText(String.valueOf(temp));
temp is a size of chosen file and I'm subtracting 100 because it's the size of bytes in every step in the loop.
The problem is when I start sending file, Button3 is grayed till the end of sending doing nothing visible with label (like it is too slow to update the label on time) but at the end it's displaying a right data.
Why it can't periodically update the label? What should I do to fix that? Thanks for any advice.
You're probably doing the I/O on the Event Dispatch Thread, which is preventing the UI from processing its normal paint events. If you have a long-running operation, you shouldn't be doing it on the EDT (e.g. by doing it in an listener like ActionListener for a button click).
You need to do this work in a background thread and send updates to the UI. An easy way to do that is to use SwingWorker. Put the long-running code in doInBackground(). Call publish(byteCount) when you read some byteCount bytes. And then in process() update the progress bar.
Here's an example of SwingWorker that updates a JProgressBar: java update progressbar
Related
I'm trying to figure out how to make a JProgressBar fill up as a file is being read. More specifically I need to read in 2 files and fill 2 JProgressBars, and then stop after one of the files has been read.
I am having trouble understanding how to make that work with a file. With two threads I would just put a for(int i = 0; i < 100; i++)loop and setValue(i) to get the current progress. But with files I don't know how to set the progress. Maybe get the size of the file and try something with that? I am really not sure and was hoping someone could throw and idea or two my way.
Thank you!
Update for future readers:
I managed to solve it by using a file.length() which returned the size of the file in bytes, then setting the bar to go from 0 to that size instead of the regular 100, and then using
for(int i = 0; i < fileSize; i++)
To get the bar loading like it should.
Example usage of ProgressMonitorInputStream. It automatically display simple dialog with progressbar if reading from InputStream takes longer - you can adjust that time by using: setMillisToPopup, setMillisToDecideToPopup.
public static void main(String[] args) {
JFrame mainFrame = new JFrame();
mainFrame.setSize(640, 480);
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainFrame.setVisible(true);
String filename = "Path to your filename"; // replace with real filename
File file = new File(filename);
try (FileInputStream inputStream = new FileInputStream(file);
ProgressMonitorInputStream progressInputStream = new ProgressMonitorInputStream(mainFrame, "Reading file: " + filename, inputStream)) {
byte[] buffer = new byte[10]; // Make this number bigger - 10240 bytes for example. 10 is there to show how that dialog looks like
long totalReaded = 0;
long totalSize = file.length();
int readed = 0;
while((readed = progressInputStream.read(buffer)) != -1) {
totalReaded += readed;
progressInputStream.getProgressMonitor().setNote(String.format("%d / %d kB", totalReaded / 1024, totalSize / 1024));
// Do something with data in buffer
}
} catch(IOException ex) {
System.err.println(ex);
}
}
So I'm getting started with javafx and I was wondering the following:
Lets say I have an application with some container inside.
For example:
VBox vBox = new VBox();
And I also have an FXML file which contains some other component I want to add to vBox multiple times.
Now I could do something like:
for(int i = 0; i < 8; i++) {
vBox.getChildren().add(FXMLLoader.load(getClass().getResource("/someComponent.fxml")));
}
But this seems very inefficient to me because every time I add the component, it gets reread from the file.
Is there any way to construct a FXMLLoader that reads the file only once, saves it in some way, and lets me generate new instances of the component as definded in the file?
There's no built-in way to do this. Tom Schindl was working on a project to convert FXML to java source and compile the source at build time. I don't know what the current status of that project is (the link I provided has a download, but he says functionality is not complete).
For a desktop application, this is unlikely to be an issue; at worst (in the vast majority of use cases) it is only going to be done at startup time or in response to user input (which in the latter case is not frequent). So it is probably not an issue.
Having said that, it is a slow process. There are two distinct issues for performance: one is reading the file (or other resource); the second is parsing the fxml (which uses copious amounts of reflection).
If you do have performance issues doing this, you could just move the component that is repeatedly loaded from fxml to Java.
If accessing the resource is the bottleneck (and I really wouldn't do this unless you have strong evidence that this is an issue; I think this is unlikely to be a cause of performance problems unless you are loading FXML from a remote location), and you want to keep it in FXML, you could load the FXML into memory and the let the FXMLLoader read from a ByteArrayInputStream:
URL fxmlResource = getClass().getResource("/SomeComponent.fxml") ;
InputStream inputStream = fxmlResource.openStream();
byte[] buffer = new byte[8192];
int totalBytes = 0 ;
int bytesRead ;
while((bytesRead = inputStream.read(buffer, totalBytes, buffer.length - totalBytes)) != -1) {
totalBytes += bytesRead ;
if (totalBytes == buffer.length) {
byte[] newBuffer = new byte[2 * buffer.length];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer ;
}
}
inputStream.close();
byte[] content = new byte[totalBytes];
System.arraycopy(buffer, 0, content, 0, totalBytes);
InputStream fxml = new ByteArrayInputStream(content);
VBox vbox = new VBox(5);
for(int i = 0; i < 8; i++) {
FXMLLoader loader = new FXMLLoader();
fxml.reset();
vBox.getChildren().add(loader.load(fxml));
}
I am using Java function to download file from internet.
public void getLatestRelease()
{
try
{
// Function called
long startTime = System.currentTimeMillis();
// Open connection
System.out.println("Connecting...");
URL url = new URL(latestReleaseUrl);
url.openConnection();
// Download routine
InputStream reader = url.openStream();
FileOutputStream writer = new FileOutputStream("release.zip");
byte[] buffer = new byte[153600];
int totalBytesRead = 0;
int bytesRead = 0;
while ((bytesRead = reader.read(buffer)) > 0)
{
writer.write(buffer, 0, bytesRead);
buffer = new byte[153600];
totalBytesRead += bytesRead;
}
// Download finished
long endTime = System.currentTimeMillis();
// Output download information
System.out.println("Done.");
System.out.println((new Integer(totalBytesRead).toString()) + " bytes read.");
System.out.println("It took " + (new Long(endTime - startTime).toString()) + " milliseconds.");
// Close input and output streams
writer.close();
reader.close();
}
// Here I catch MalformedURLException and IOException :)
}
And I have JProgressBar component in my JPanel, which is supposed to visualize download progress:
private static void createProgressBar(JPanel panel)
{
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
progressBar.setStringPainted(true);
panel.add(progressBar, BorderLayout.SOUTH);
}
I'd like to separate "back-end" functions from "front-end" views, presented to users, by analogy with MVC in web applications.
So, function getLatestRelease() lies in the package framework in class MyFramework.
Everything, connected with Swing interface generation, including event listeners, is in the package frontend.
In the main Controller class I create an instance of MyFramework and an instance of ApplicationFrontend, which is the main class of frontend package.
The questions is how to update progressBar value, depending on download progress?
when you want to do MVC in swing, the SwingWorker class comes to mind.
SwingWorker comes with a property called "progress", that you can listen to using a PropertyChangeListener.
Progress events can be fired from the swingworker using its setProgress(int 0-100) method. So here it is for loading the file in the background with a notion of progress (note that you will need to have an idea of the size of the file to be able to compute a progress percentage).
Showing the progress can be done using two options : a JProgressBar for complete control, or a ProgressMonitor to show an almost self-managed popup with a progress bar in it. See the tutorial to see the differences.
Solution 1
As they say, if you go for a ProgressMonitor and your background task is reading from an InputStream, you can use the ProgressMonitorInputStream class to do the reading and displaying progress without bothering with calling setProgress or listening to the "progress" property.
Solution 2
If you want to do it manually, create your SwingWorker loading task that calls setProgress as it goes, instanciate a ProgressMonitor (or a JProgressBar) as needed, register a PropertyChangeListener on your SwingWorker that checks for "progress" changes and updates the monitor/bar accordingly.
Note: It is important to go through a PropertyChangeListener because it decouples the model (the task) from the view (the swing progress component) and abide by the EDT usage rules.
I am making a sort of Macro recorder/player
I have done the player part with utils such as java.awt.Robot() which emulates basic human mouse/keyboard output commands, reading an XML file.
I am stuck at the part where I have to record that XML file.
I have no idea of which Class I can use to do the opposite of Robot() If yo have any FemaleRobot() for me I would be very happy :D
The only thing in this direction I have so far is :
while (true) {
Point pos = MouseInfo.getPointerInfo().getLocation();
System.out.println(pos.x+" x "+pos.y);
}
which is not much and not really what I want ^_^, I don't know how to use a Mouse/KeyListener since it would require a Component. If it is the only way, what Compoment do I use as I don't want any graphical java implementation? Should I create a phony Component anyway? Which one?
e.g. I want my recorder to write in the XML how I click on my ubuntu desktop or press enter on firefox.
I guess it's clear, if not I will be checking the answers a lot. Have a nice day and thanks for reading this.
Try jnativehook lib:
http://code.google.com/p/jnativehook/wiki/examples
It is very easy to use and may meet your needs.
I regret to inform you it is completely impossible to monitor mouse clicks and keystrokes outside of your form. Java events simply do not fire outside the scope of your form.
The reason java behaves this way is to eliminate the possibility of java based malware attempting to steal sensitive data.
You can find examples of mouse listeners here: http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
to Write to a file you can do something like:
FileWriter fileStream = new FileWriter("myfile.extention");
BufferedWriter out = new BufferedWriter(fileStream);
out.write("pos.x+" x "+pos.y");
If you are doing this:
while (true)
{
Point pos = MouseInfo.getPointerInfo().getLocation();
System.out.println(pos.x+" x "+pos.y);
}
You will want to add a Thread.Sleep call in the loop.
Then you can read the file back by doing:
FileInputStream fileStream = new FileInputStream("myfile.extention");
DataInputStream in = new DataInputStream(fileStream);
BufferedReader br = new BufferedReader(new InputStreamReader(in))
String position = br.readLine()
Then you can parse that string to get the values.
So you might do something like:
FileWriter filewrite = new FileWriter("myfile.txt");
BufferedWriter out = new BufferedWriter(filewrite);
while (Recording)
{
Point pos = MouseInfo.getPointerInfo().getLocation();
out.write(pos.x + " " + pos.y);
Thread.sleep(50);
}
FileInputStream fileStream = new FileInputStream("myfile.txt");
DataInputStream in = new DataInputStream(fileStream);
BufferedReader br = new BufferedReader(new InputStreamReader(in))
String position;
while(position = br.readLine() != null)
{
String[] positions = position.split(" ");
int x = Integer.parseInt(positions[0]);
int y = Integer.parseInt(positions[1]);
}
You will have to use the mouse events to write click positions to the file.
You can first get the resolution of screen.Second thing make a frame that is a size of your screen and make its transparency to 0% .When you click to a position on a screen put down your jframe and use mouse robot to click a position.You can get the coordinates of the entire screen.This way you can record the mouse clicks,But the problem comes is when you need to type in the text
I have a strange phenomenon when resuming a file transfer.
Look at the picture below you see the bad section.
This happens apparently random, maybe every 10:th time.
Im sending the picture from my Android phone to java server over ftp.
What is it that i forgot here.
I see the connection is killed due to java.net.SocketTimeoutException:
The transfer is resuming like this
Resume at : 287609 Sending 976 bytes more
The bytes are always correct when file is completely received.
Even for the picture below.
Dunno where to start debug this since its working most of the times.
Any suggestions or ideas would be grate i think i totally missed something here.
The device Sender code (only send loop):
int count = 1;
//Sending N files, looping N times
while(count <= max) {
String sPath = batchFiles.get(count-1);
fis = new FileInputStream(new File(sPath));
int fileSize = bis.available();
out.writeInt(fileSize); // size
String nextReply = in.readUTF();
// if the file exist,
if(nextReply.equals(Consts.SERVER_give_me_next)){
count++;
continue;
}
long resumeLong = 0; // skip this many bytes
int val = 0;
buffer = new byte[1024];
if(nextReply.equals(Consts.SERVER_file_exist)){
resumeLong = in.readLong();
}
//UPDATE FOR #Justin Breitfeller, Thanks
long skiip = bis.skip(resumeLong);
if(resumeLong != -1){
if(!(resumeLong == skiip)){
Log.d(TAG, "ERROR skip is not the same as resumeLong ");
skiip = bis.skip(resumeLong);
if(!(resumeLong == skiip)){
Log.d(TAG, "ERROR ABORTING skip is not the same as resumeLong);
return;
}
}
}
while ((val = bis.read(buffer, 0, 1024)) > 0) {
out.write(buffer, 0, val);
fileSize -= val;
if (fileSize < 1024) {
val = (int) fileSize;
}
}
reply = in.readUTF();
if (reply.equals(Consts.SERVER_file_receieved_ok)) {
// check if all files are sent
if(count == max){
break;
}
}
count++;
}
The receiver code (very truncated):
//receiving N files, looping N times
while(count < totalNrOfFiles){
int ii = in.readInt(); // File size
fileSize = (long)ii;
String filePath = Consts.SERVER_DRIVE + Consts.PTPP_FILETRANSFER;
filePath = filePath.concat(theBatch.getFileName(count));
File path = new File(filePath);
boolean resume = false;
//if the file exist. Skip if done or resume if not
if(path.exists()){
if(path.length() == fileSize){ // Does the file has same size
logger.info("File size same skipping file:" + theBatch.getFileName(count) );
count++;
out.writeUTF(Consts.SERVER_give_me_next);
continue; // file is OK don't upload it again
}else {
// Resume the upload
out.writeUTF(Consts.SERVER_file_exist);
out.writeLong(path.length());
resume = true;
fileSize = fileSize-path.length();
logger.info("Resume at : " + path.length() +
" Sending "+ fileSize +" bytes more");
}
}else
out.writeUTF("lets go");
byte[] buffer = new byte[1024];
// ***********************************
// RECEIVE FROM PHONE
// ***********************************
int size = 1024;
int val = 0;
bos = new BufferedOutputStream(new FileOutputStream(path,resume));
if(fileSize < size){
size = (int) fileSize;
}
while (fileSize >0) {
val = in.read(buffer, 0, size);
bos.write(buffer, 0, val);
fileSize -= val;
if (fileSize < size)
size = (int) fileSize;
}
bos.flush();
bos.close();
out.writeUTF("file received ok");
count++;
}
Found the error and the problem was bad logic from my part.
say no more.
I was sending pictures that was being resized just before they where sent.
The problem was when the resume kicked in after a failed transfer
the resized picture was not used, instead the code used the original
pictured that had a larger scale size.
I have now setup a short lived cache that holds the resized temporary pictures.
In the light of the complexity of the app im making I simply forgot that the files during resume was not the same as original.
With a BufferedOutputStream, BufferedInputStream, you need to watch out for the following
Create BufferedOutputStream before BuffererdInputStream (on both client and server)
And flush just after create.
Flush after every write (not just before close)
That worked for me.
Edited
Add sentRequestTime, receivedRequestTime, sentResponseTime, receivedResponseTime to your packet payload. Use System.nanoTime() on these, run your server and client on the same host, use ExecutorService to run multiple clients for that server, and plot your (received-sent) for both request and response packets, time delay on a excel chart (some csv format). Do this before bufferedIOStream and afterIOStream. You will be pleased to know that your performance has boosted by 100%. Made me very happy to plot that graph, took about 45 mins.
I have also heard that using custom buffer's further improves performance.
Edited again
In my case I am using Object IOStreams, I have added a payload of 4 long variables to the object, and initialize sentRequestTime when I send the packet from the client, initialize receivedRequestTime when the server receives the response, so and so forth for the response from server to client too. I then find the difference between received and sent time to find out the delay in response and request. Be careful to run this test on localhost. If you run it between different hardware/devices, their actual time difference may interfere with your test results. Since requestReceivedTime is time stamped at the server end and the requestSentTime is time stamped at the client end. In other words, their own local time is stamped (obviously). And both of these devices running the exact same time to the nano second is not possible. If you must run it between different devices atleast make sure that you have ntp running (to keep them time synchronized). That said, you hare comparing the performance before and after bufferedio (you dont really care about the actual time delays right ?), so time drift should not really matter. Comparing a set of results before buffered and after buffered is your actual interest.
Enjoy!!!