Implementering af en FTP-klient i Java

1. Oversigt

I denne vejledning ser vi på, hvordan man udnytter Apache Commons Net-biblioteket til at interagere med en ekstern FTP-server.

2. Opsætning

Når du bruger biblioteker, der bruges til at interagere med eksterne systemer, er det ofte en god ide at skrive nogle ekstra integrationstest for at sikre, at vi bruger biblioteket korrekt.

I dag bruger vi normalt Docker til at spinde disse systemer op til vores integrationstest. Men især når det bruges i passiv tilstand, er en FTP-server ikke den nemmeste applikation til at køre gennemsigtigt inde i en container, hvis vi ønsker at gøre brug af dynamiske porttilknytninger (hvilket ofte er nødvendigt for, at tests kan køres på en delt CI-server ).

Derfor bruger vi i stedet MockFtpServer, en Fake / Stub FTP-server skrevet i Java, der giver en omfattende API til nem brug i JUnit-tests:

 commons-net commons-net 3.6 org.mockftpserver MockFtpServer 2.7.1 test 

Det anbefales altid at bruge den nyeste version. Disse kan findes her og her.

3. FTP-support i JDK

Overraskende nok er der allerede grundlæggende support til FTP i nogle JDK-smag i form af sun.net.www.protocol.ftp.FtpURLConnection.

Vi bør dog ikke bruge denne klasse direkte, og det er i stedet muligt at bruge JDK'erne java.net.URL-klasse som en abstraktion.

Denne FTP-understøttelse er meget grundlæggende, men udnytter de bekvemme API'er fra java.nio.file.Files, det kunne være nok til simple brugssager:

@Test offentlig ugyldighed givenRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem () kaster IOException {String ftpUrl = String.format ("ftp: // user: [email protected]:% d / foobar.txt", fakeFtpServer.getServerControlPort;) URLConnection urlConnection = ny URL (ftpUrl). OpenConnection (); InputStream inputStream = urlConnection.getInputStream (); Files.copy (inputStream, ny fil ("downloaded_buz.txt"). ToPath ()); inputStream.close (); assertThat (ny fil ("downloaded_buz.txt")). eksisterer (); ny fil ("downloaded_buz.txt"). slet (); // Ryd op }

Da denne grundlæggende FTP-understøttelse allerede mangler grundlæggende funktioner som filoversigter, skal vi bruge FTP-understøttelse i Apache Net Commons-biblioteket i de følgende eksempler.

4. Tilslutning

Vi skal først oprette forbindelse til FTP-serveren. Lad os starte med at oprette en klasse FtpClient.

Det fungerer som en abstraktion API til den faktiske Apache Commons Net FTP-klient:

klasse FtpClient {privat strengserver; privat int port; privat streng bruger; privat strengadgangskode; privat FTPClient ftp; // konstruktør ugyldig åben () kaster IOException {ftp = ny FTPClient (); ftp.addProtocolCommandListener (ny PrintCommandListener (ny PrintWriter (System.out))); ftp.connect (server, port); int svar = ftp.getReplyCode (); hvis (! FTPReply.isPositiveCompletion (svar)) {ftp.disconnect (); smid ny IOException ("Undtagelse ved tilslutning til FTP-server"); } ftp.login (bruger, adgangskode); } ugyldigt tæt () kaster IOException {ftp.disconnect (); }}

Vi har brug for serveradressen og porten samt brugernavnet og adgangskoden. Efter tilslutning er det nødvendigt faktisk at kontrollere svarskoden for at være sikker på, at forbindelsen var vellykket. Vi tilføjer også en PrintCommandListener, for at udskrive de svar, vi normalt ser, når vi opretter forbindelse til en FTP-server ved hjælp af kommandolinjeværktøjer til stdout.

Da vores integrationstest vil have en kedelpladekode, som at starte / stoppe MockFtpServer og tilslutte / afbryde vores klient, kan vi gøre disse ting i @Før og @Efter metoder:

offentlig klasse FtpClientIntegrationTest {privat FakeFtpServer fakeFtpServer; private FtpClient ftpClient; @Før offentlig ugyldig opsætning () kaster IOException {fakeFtpServer = ny FakeFtpServer (); fakeFtpServer.addUserAccount (ny UserAccount ("bruger", "adgangskode", "/ data")); FileSystem fileSystem = nyt UnixFakeFileSystem (); fileSystem.add (ny DirectoryEntry ("/ data")); fileSystem.add (ny FileEntry ("/ data / foobar.txt", "abcdef 1234567890")); falskeFtpServer.setFileSystem (fileSystem); falskeFtpServer.setServerControlPort (0); falskeFtpServer.start (); ftpClient = ny FtpClient ("localhost", fakeFtpServer.getServerControlPort (), "bruger", "adgangskode"); ftpClient.open (); } @Efter offentlig ugyldig nedrivning () smider IOException {ftpClient.close (); falskeFtpServer.stop (); }}

Ved at indstille mock-serverens kontrolport til værdien 0 starter vi mock-serveren og en gratis tilfældig port.

Derfor er vi nødt til at hente den aktuelle port, når vi opretter FtpClient efter serveren er startet ved hjælp af fakeFtpServer.getServerControlPort ().

5. Notering af filer

Den første faktiske brugssag vil være en liste over filer.

Lad os starte med testen først, TDD-stil:

@Test offentlig ugyldighed givenRemoteFile_whenListingRemoteFiles_thenItIsContainedInList () kaster IOException {Collection files = ftpClient.listFiles (""); assertThat (filer). indeholder ("foobar.txt"); }

Selve implementeringen er lige så ligetil. For at gøre den returnerede datastruktur lidt enklere af hensyn til dette eksempel transformerer vi den returnerede FTPFile array transformeres til en liste over Strenge ved hjælp af Java 8 Strømme:

SamlingslisteFiler (strengsti) kaster IOException {FTPFile [] filer = ftp.listFiles (sti); returnere Arrays.stream (filer) .map (FTPFile :: getName) .collect (Collectors.toList ()); }

6. Downloading

For at downloade en fil fra FTP-serveren definerer vi en API.

Her definerer vi kildefilen og destinationen på det lokale filsystem:

@Test offentlig ugyldighed givetRemoteFile_whenDownloading_thenItIsOnTheLocalFilesystem () kaster IOException {ftpClient.downloadFile ("/ buz.txt", "downloaded_buz.txt"); assertThat (ny fil ("downloaded_buz.txt")). eksisterer (); ny fil ("downloaded_buz.txt"). slet (); // Ryd op }

Apache Net Commons FTP-klienten indeholder en praktisk API, der direkte skriver til en defineret OutputStream. Dette betyder, at vi kan bruge dette direkte:

ugyldig downloadFile (strengkilde, strengdestination) kaster IOException {FileOutputStream ud = ny FileOutputStream (destination); ftp.retrieveFile (kilde, ud); }

7. Uploading

MockFtpServer giver nogle nyttige metoder til at få adgang til indholdet af dets filsystem. Vi kan bruge denne funktion til at skrive en simpel integrationstest til uploadfunktionen:

@Test offentlig ugyldighed givetLocalFile_whenUploadingIt_thenItExistsOnRemoteLocation () kaster URISyntaxException, IOException {File file = new File (getClass (). GetClassLoader (). GetResource ("baz.txt"). ToURI ()); ftpClient.putFileToPath (fil, "/buz.txt"); assertThat (fakeFtpServer.getFileSystem (). findes ("/ buz.txt")). isTrue (); }

Uploading af en fil fungerer API-vis meget lig at downloade den, men i stedet for at bruge en OutputStream, skal vi give en InputStream i stedet:

ugyldigt putFileToPath (filfil, strengsti) kaster IOException {ftp.storeFile (sti, ny FileInputStream (fil)); }

8. Konklusion

Vi har set, at brug af Java sammen med Apache Net Commons giver os mulighed for let at interagere med en ekstern FTP-server for både læsning og skriveadgang.

Som sædvanlig er den komplette kode til denne artikel tilgængelig i vores GitHub-arkiv.


$config[zx-auto] not found$config[zx-overlay] not found