/* * [BulkFTP.java] * * Summary: Upload a large set of files with FTP avoiding those already uploaded. * * Copyright: (c) 2011-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2011-12-03 initial release */ package com.mindprod.bulkftp; import com.enterprisedt.net.ftp.AdvancedFTPSettings; import com.enterprisedt.net.ftp.FTPConnectMode; import com.enterprisedt.net.ftp.FTPException; import com.enterprisedt.net.ftp.FTPFile; import com.enterprisedt.net.ftp.FTPTransferType; import com.enterprisedt.net.ftp.FileTransferClient; import com.enterprisedt.net.ftp.WriteMode; import com.mindprod.common18.EIO; import com.mindprod.filter.ExtensionListFilter; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.text.ParseException; import java.util.Arrays; import java.util.Iterator; import static java.lang.System.*; /** * Upload a large set of files with FTP avoiding those already uploaded. *
* requires edtftpj.jar both to compile and to run. from http://enterprisedt.com/products/edtftpj/ * needs to be installed in ext directory. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2011-12-03 initial release * @since 2011-12-03 */ public class BulkFTP { /** * when this version was released */ @SuppressWarnings( { "UnusedDeclaration" } ) static final String RELEASE_DATE = "2011-12-11"; /** * embedded version string */ @SuppressWarnings( { "UnusedDeclaration" } ) static final String VERSION_STRING = "1.0"; private static final int FIRST_COPYRIGHT_YEAR = 2011; /** * how frequently to save, in case we crash */ private static final int HOW_OFTEN_TO_SAVE = 50; /** * which directory we are processing, webroot relative */ private static final String DIR = "politics"; /** * undisplayed copyright notice */ @SuppressWarnings( { "UnusedDeclaration" } ) private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2011-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * temporary filter */ static FilenameFilter filter = new ExtensionListFilter( "html", "zip", "xml" ); /** * count of files deleted */ private static int countOfFilesDeleted; /** * count of files uploaded */ private static int countOfFilesUploaded; /** * connection to server, control and date sockets */ private static FileTransferClient ftc; /** * connect to the server * * @throws FTPException if trouble connecting * @throws IOException */ private static void connect() throws FTPException, IOException { ftc = new FileTransferClient(); // caonnot recycle final AdvancedFTPSettings advancedFTPSettings = ftc.getAdvancedFTPSettings(); advancedFTPSettings.setConnectMode( Config.PASV ? FTPConnectMode.PASV : FTPConnectMode.ACTIVE ); advancedFTPSettings.setStrictReturnCodes( false ); advancedFTPSettings.setActivePortRange( Config.FTP_PORT_LOW, Config.FTP_PORT_HIGH ); ftc.setRemoteHost( Config.HOST ); ftc.setUserName( Config.USER_NAME ); ftc.setPassword( Config.PASSWORD ); ftc.setContentType( FTPTransferType.BINARY ); // So lengths on client and server will match exactly ftc.connect(); ftc.changeDirectory( Config.SERVER_ROOT_DIR ); } /** * delete files from server that no longer exists on client. * * @param filesToDelete files to delete from server * * @throws java.io.IOException if trouble with local file * @throws com.enterprisedt.net.ftp.FTPException if trouble with server file */ private static void deleteFilesFromServer( @NotNull FD[] filesToDelete ) throws FTPException, IOException { for ( FD fd : filesToDelete ) { out.println( "Deleting " + fd.getFilenameWithSlashes() ); ftc.deleteFile( fd.getFilenameWithSlashes() ); // values of last scan, might be out of date. Could retest. Will be retested on next run. fd.setLastModifiedOnServer( System.currentTimeMillis() ); fd.setSizeOnClient( -1 ); fd.setSizeOnServer( -1 ); countOfFilesDeleted++; } } /** * find files that need to be deleted from the server * * @return array of FDs to delete. */ @NotNull private static FD[] findFilesToDeleteFromServer() { // we have to scan twice, but we avoid ArrayList and memory estimate. int countOfFilesToDelete = 0; for ( FD fd : FD.values() ) { if ( fd.getSizeOnClient() < 0 && fd.getSizeOnServer() >= 0 ) { countOfFilesToDelete++; } } final FD[] filesToDelete = new FD[ countOfFilesToDelete ]; int j = 0; for ( FD fd : FD.values() ) { if ( fd.getSizeOnClient() < 0 && fd.getSizeOnServer() >= 0 ) { filesToDelete[ j++ ] = fd; } } Arrays.sort( filesToDelete ); return filesToDelete; } /** * find files with different size or newer date that need to be uploaded * * @return array of FDs to upload. */ @NotNull private static FD[] findFilesToUpload() { // we have to scan twice, but we avoid ArrayList and memory estimate. int countOfFilesToUpload = 0; for ( FD fd : FD.values() ) { if ( fd.getSizeOnClient() >= 0 && ( fd.getLastModifiedOnClient() > fd.getLastModifiedOnServer() || fd.getSizeOnClient() != fd.getSizeOnServer() ) ) { countOfFilesToUpload++; } } final FD[] filesToUpload = new FD[ countOfFilesToUpload ]; int j = 0; for ( FD fd : FD.values() ) { if ( fd.getSizeOnClient() >= 0 && ( fd.getLastModifiedOnClient() > fd.getLastModifiedOnServer() || fd.getSizeOnClient() != fd.getSizeOnServer() ) ) { filesToUpload[ j++ ] = fd; } } Arrays.sort( filesToUpload ); return filesToUpload; } /** * prune files already deleted from local disk and server */ private static void pruneDeadwood() { for ( Iterator