I am trying to write a service which will copy multiple files from one network location to local project file , while i am running the code i am having below observations
- If there is only one file and say it is of 520kb while copying through the network we are having 519kb.
- If there are multiple files the files are copied into the local project path but all of them are of 0kb and only the last file from the network is having data rest are 0kb .
- The Files are initially 0kb but after sometimes they are showing actual size.
I am not able to understand the issue here below is my code
@Override @SneakyThrows public boolean createCopyOnNetwork()throws Exception { boolean isAbleToCopy =false; List<ChannelSftp.LsEntry> files = findFile(getChannelUsingSftp(), filemask); byte[] buffer = new byte[1024]; for(ChannelSftp.LsEntry entry : files) { bis = new BufferedInputStream(getChannelUsingSftp().get(entry.getFilename())); newFile = new File("downloadedFiles\"+entry.getFilename()); os = new FileOutputStream(newFile); bos = new BufferedOutputStream(os); while( (readCount = bis.read(buffer)) > 0) { bos.write(buffer, 0, readCount); isAbleToCopy=true; } } return isAbleToCopy; } public List<ChannelSftp.LsEntry> findFile(ChannelSftp sftpChannel, String filemask) throws SftpException, JSchException { LOG.info("Getting file List using findFile "); List<ChannelSftp.LsEntry> list = getChannelUsingSftp().ls(filemask); return list; } public ChannelSftp getChannelUsingSftp() throws JSchException, SftpException { LOG.info("Getting Sftp"); channel = getSessionOnNetwork(smbUsername,host,port).openChannel("sftp"); channel.connect(); ChannelSftp sftpChannel = (ChannelSftp)channel; sftpChannel.cd(smbPath); return sftpChannel; } public Session getSessionOnNetwork(String smbUsername,String host,int port) throws JSchException { LOG.info("Getting session on Network"); session= jsch.getSession(smbUsername,host,port); session.setConfig("StrictHostKeyChecking", "no"); session.setPassword(smbPassword); session.connect(); return session; } }
Advertisement
Answer
You missing calls to close()
each stream after EACH use inside the loop. Using try with resources will help clean-up all streams immediately after use, and change code structure to make use of built in calls of InputStream
and Files
.
for(ChannelSftp.LsEntry entry : files) { Path path = Path.of("downloadedFiles",entry.getFilename()); try(InputStream is = getChannelUsingSftp().get(entry.getFilename()); OutputStream os = Files.newOutputStream(path)) { is.transferTo(os); isAbleToCopy=true; } }
You may find that there is a second issue here relating to use of getChannelUsingSftp()
inside the loop, so that each file retrieval makes a reconnection to ftp server and is not re-using the connection made to same server when generating the list of files as for findFile
. Assigning to a local variable should help avoid excessive server connections:
ChannelSftp ftp = getChannelUsingSftp();