我正在尝试在通信错误/超时等情况下实现ftp上传的回退机制。实际上我想要实现的是,如果文件正在上传(使用调度程序)并且我有连接失败那么这个下次调度程序要尝试上传文件时应该能够重新启动文件上传。
所以我的调度程序每X分钟调用一个方法,该方法轮询目录以检索要发送的文件:
public void sendZippFiles() throws IOException, Exception {
...
if (directoryListing2 != null) {
for (File child : directoryListing2) {
...
StudyDetailsDAO studyDetailsDAO = new StudyDetailsDAOImpl();
TransferFileFtp ftpTransfer = new TransferFileFtp();
// check if the file is in progress of uploading
Boolean isInProgress = studyDetailsDAO.checkStudyDetailsIsInProgress(tmpStr);
// check if the file is registered in local db - only registered files should be send
Boolean studyExist = studyDetailsDAO.checkStudyDetailsExists(tmpStr);
if(!isInProgress && child1.exists() && !child1.isDirectory() && studyExist) {
// set flag true to mark that the file is in progress of uploading
studyDetailsDAO.updateStudyIsInProgress(tmpStr, true);
// try and upload the file by calling a method to upload the file
Boolean toFtpTransfer = ftpTransfer.uploadFileFtp3(child1);
if (toFtpTransfer==true) {
//if success then a) rename remote file and delete file from local directory
ftpTransfer.renameFileFtp3(child1);
boolean delete = child1.delete();
//if success then update required flags to db
if(child1.toPath().toString().endsWith(".zip")) {
try {
studyDetailsDAO.updateStudyIsUploaded(tmpStr, true);
studyDetailsDAO.updateStudyIsInProgress(tmpStr, false);
studyDetailsDAO.updateIsReadyToProccess(tmpStr, false);
} catch(Exception e){
// if any error occurs
System.out.println("Error sending the file!");
e.printStackTrace();
toFtpTransfer = false;
}
} else {
System.out.println("Error in file type!");
child1.delete();
}
} else {
System.out.println("An error occured during file upload...");
// maybe here we should try and set IsInProgress to FALSE
studyDetailsDAO.updateStudyIsInProgress(tmpStr, false);
}
....
以下是上传文件的方法:ftpTransfer.uploadFileFtp3(文件)
public Boolean uploadFileFtp3(File sendFile) {
Boolean ftpStatus = false;
....
FTPClient ftpClient = new FTPClient();
try {
...
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setBufferSize(1024000);
File secondLocalFile = new File(sendFile.getCanonicalPath());
String secondRemoteFile = config.getFtpRemoteFolderUploads()+sendFile.getName()+".part";
InputStream inputStream = new FileInputStream(secondLocalFile);
System.out.println("Start uploading file");
OutputStream outputStream = ftpClient.storeFileStream(secondRemoteFile);
byte[] bytesIn = new byte[4096];
int read = 0;
int cc = 0;
long fileSize = secondLocalFile.length();
System.out.println("Start uploading file with size: " + fileSize);
while ((read = inputStream.read(bytesIn)) != -1) {
outputStream.write(bytesIn, 0, read);
System.out.println("Uploaded: " + read*(cc+1) + " of " + fileSize + " of file: " + sendFile.getName());
cc++;
}
inputStream.close();
outputStream.close();
boolean completed = ftpClient.completePendingCommand();
if (completed) {
System.out.println("The file is uploaded successfully.");
ftpStatus = true;
}
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
error = true;
ex.printStackTrace();
System.out.println("Going to update IsInProgress status for study: " + stdId);
studyDetailsDAO.updateStudyIsInProgress(stdId, false);
ftpStatus = false;
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return ftpStatus;
}
因此,问题如下:如果文件上传被中断(通信错误),下次调度程序尝试重新启动其上载时,我收到NullPointerException:
Start uploading file
Start uploading file with size: 23783382
Ιαν 22, 2015 2:15:58 ΜΜ com.npap.dicomrouter2.FXMLDocumentController RunScheduledTasks
SEVERE: null
java.lang.NullPointerException
at com.npap.network.TransferFileFtp.uploadFileFtp3(TransferFileFtp.java:240)
at com.npap.utils.ProcessDicomFiles.sendZippFiles(ProcessDicomFiles.java:165)
at com.npap.dicomrouter2.FXMLDocumentController.RunScheduledTasks(FXMLDocumentController.java:290)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1757)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1645)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8216)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3724)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3452)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1728)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2461)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:348)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:273)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:382)
at com.sun.glass.ui.View.handleMouseEvent(View.java:553)
at com.sun.glass.ui.View.notifyMouse(View.java:925)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$37/128893786.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
我收到错误的地方是我在上传文件方法中写入outputStream的地方:
while ((read = inputStream.read(bytesIn)) != -1) {
outputStream.write(bytesIn, 0, read);
System.out.println("Uploaded: " + read*(cc+1) + " of " + fileSize + " of file: " + sendFile.getName());
cc++;
}
我在这里缺少什么?我应该以某种方式重新创建一个新的OutputStream对象?这是问题吗?