文档章节

Apache commons ftp API 的Spike

XzhiF
 XzhiF
发布于 2013/12/13 12:23
字数 2318
阅读 1.5K
收藏 9

由于公司给了我一个传FTP的任务,刚好可以学习一下,同时也进行了一些单元测试,spike了一把,哈哈。分享一下。

这里只对最简单常用的FtpClient的上传下载列表功能进行测试学习使用^-^

创建一个maven工程

在工作根目录创建目录

工程path/res/log

工程path/res/ftphome

配置pom文件。

<dependencies>
		<dependency>
			<groupId>org.apache.ftpserver</groupId>
			<artifactId>ftpserver-core</artifactId>
			<version>1.0.6</version>
		</dependency>


		<dependency>
			<groupId>commons-net</groupId>
			<artifactId>commons-net</artifactId>
			<version>3.3</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.5.2</version>
		</dependency>

		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.14</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
配置创建一个log4j.properties文件,放在src/test/resource下
log4j.rootLogger=INFO, stdout ,R 

log4j.appender.R=org.apache.log4j.RollingFileAppender 
log4j.appender.R.File=./res/log/ftpd.log
log4j.appender.R.MaxFileSize=10MB 
log4j.appender.R.MaxBackupIndex=10 
log4j.appender.R.layout=org.apache.log4j.PatternLayout 
log4j.appender.R.layout.ConversionPattern=[%5p] %d [%X{userName}] [%X{remoteIp}] %m%n

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}-%m%n
在src/test/resource下

创建一个目录upload/

存放两个文件 upload/rober.c.martin.jpg, upload/excel.xslx

还是在src/test/resource下加一个myusers.properties文件

ftpserver.user.test.userpassword=test
ftpserver.user.test.homedirectory=./res/ftphome
ftpserver.user.test.enableflag=true
ftpserver.user.test.writepermission=true
ftpserver.user.test.maxloginnumber=3
ftpserver.user.test.maxloginperip=3
ftpserver.user.test.idletime=0
ftpserver.user.test.uploadrate=0
ftpserver.user.test.downloadrate=0
一切准备好了,首先我们来测试FtpServer的启动

src/test/java/com/fengzidm/spike/ftp/TestFtpServer.java

package com.fengzidm.spike.ftp;

import static org.junit.Assert.*;

import java.io.File;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class TestFtpServer
{

	private static final String HOST = "127.0.0.1";
	private static final int PORT = 2222;
	
	 // 与myusers.properties配置相结合

        private static final String USERNAME = "test";
	private static final String PASSWORD = "test";

	private static FtpServer server;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		try
		{
			FtpServerFactory serverFactory = new FtpServerFactory();

			ListenerFactory listenerFactory = new ListenerFactory();
			listenerFactory.setPort( PORT );
			// replace the default listener
			serverFactory.addListener( "default", listenerFactory.createListener() );

			PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
			userManagerFactory.setFile( new File( "myusers.properties" ) );
			
			 //设置为不加密码形式的密码
			userManagerFactory.setPasswordEncryptor( new ClearTextPasswordEncryptor() );
			serverFactory.setUserManager( userManagerFactory.createUserManager() );

			server = serverFactory.createServer();
			server.start();
		}
		catch ( Exception e )
		{
			e.printStackTrace();
			fail( e.getMessage() );
		}
	}

	@Test
	public void testConnect() throws Exception
	{

		FTPClient ftpClient = new FTPClient();
		ftpClient.connect( HOST, PORT );

		Integer replyCode = ftpClient.getReplyCode();
	
		//连接成功状态码为220
		assertEquals( new Integer( 220 ), replyCode );
	}

	@Test
	public void testLoginSuccess() throws Exception
	{
		FTPClient ftpClient = new FTPClient();
		ftpClient.connect( HOST, PORT );
		boolean result = ftpClient.login( USERNAME, PASSWORD );
		Integer replyCode = ftpClient.getReplyCode();
		assertTrue( result );
		assertEquals( new Integer( 230 ), replyCode );
	}

	@Test
	public void testLoginFailue() throws Exception
	{
		FTPClient ftpClient = new FTPClient();
		ftpClient.connect( HOST, PORT );

		String invalidPassword = "fuck";
		boolean result = ftpClient.login( USERNAME, invalidPassword );
		Integer replyCode = ftpClient.getReplyCode();
		assertFalse( result );

		 //登录失败返回状态码530
		assertEquals( new Integer( 530 ), replyCode );
	}

	@AfterClass
	public static void tearDown() throws Exception
	{
		if ( server != null )
		{
			try
			{
				server.stop();
				System.out.println( "testing server is stop" );
			}
			catch ( Exception igonred )
			{
			}
		}
	}
}
在测试FtpClient前

根据上面

创建一个FtpTestHelper类

src/test/java/com/fengzidm/spike/ftp/FtpTestHelper.java


package com.fengzidm.spike.ftp;

import java.io.File;

import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.junit.Assert;

public class FtpTestHelper
{
	private FtpServer ftpServer;

	public void initialize( int port, String userManagerProperties )
	{
		try
		{
			FtpServerFactory serverFactory = new FtpServerFactory();

			ListenerFactory listenerFactory = new ListenerFactory();
			listenerFactory.setPort( port );
			// replace the default listener
			serverFactory.addListener( "default", listenerFactory.createListener() );

			PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
			userManagerFactory.setFile( new File( userManagerProperties ) );

			
			 // 设置为不加密码形式的密码
			userManagerFactory.setPasswordEncryptor( new ClearTextPasswordEncryptor() );
			serverFactory.setUserManager( userManagerFactory.createUserManager() );

			ftpServer = serverFactory.createServer();
		}
		catch ( Exception e )
		{
			e.printStackTrace();
			Assert.fail( "创建FtpServer失败,原因:" + e.getMessage() );
		}
	}

	public void startServer() throws FtpException
	{
		if ( ftpServer != null && ftpServer.isStopped() )
		{
			ftpServer.start();
		}
	}

	public void stopServer()
	{
		if ( ftpServer != null && !ftpServer.isStopped() )
		{
			ftpServer.stop();
		}
	}
}




创建一个TestCase类,帮组消除setUp 等这些代码

src/test/java/com/fengzidm/spike/ftp/FtpClientTestCase.java


package com.fengzidm.spike.ftp;

import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTPClient;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;

public abstract class FtpClientTestCase
{
	
	protected static final String HOST = "127.0.0.1";
	protected static final int PORT = 2222;

	//与myusers.properties配置相结合
        protected static final String USERNAME = "test";
	protected static final String PASSWORD = "test";

	protected static FtpTestHelper helper;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception
	{
		helper = new FtpTestHelper();
		helper.initialize( PORT, "myusers.properties" );
		helper.startServer();
	}

	protected FTPClient ftpClient;

	@Before
	public void setUp() throws Exception
	{
		ftpClient = new FTPClient();
		ftpClient.connect( HOST, PORT );
		boolean result = ftpClient.login( USERNAME, PASSWORD );
		assertTrue( result );
	}

	@After
	public void tearDown() throws Exception
	{
		if ( ftpClient.isConnected() )
		{
			ftpClient.disconnect();
		}
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception
	{
		helper.stopServer();
	}
	
	protected FTPClient reConnectFtpClient() throws SocketException, IOException
	{
		if ( ftpClient.isConnected() )
		{
			ftpClient.disconnect();
		}

		ftpClient = new FTPClient();
		ftpClient.connect( HOST, PORT );
		ftpClient.login( USERNAME, PASSWORD );
		return ftpClient;
	}
}
我们进行FtpClient的API简单使用的测试


src/test/java/com/fengzidm/spike/ftp/TestFtpClient.java


package com.fengzidm.spike.ftp;

import static org.junit.Assert.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPListParseEngine;
import org.junit.Test;

public class TestFtpClient extends FtpClientTestCase {

	/**
	 * 上传文本文件
	 */
	@Test
	public void testStoreTextFile() throws Exception {
		ByteArrayInputStream bais = new ByteArrayInputStream(new String("中文").getBytes("GBK"));

		
		//通过改方法指定文件名,上传,通过指定dir目录 , 可以直接上传到目录里面 重复上传,文件里面是直接累加。 不会重新写文件!
		// store操作,会重新执行会覆盖原有文件
		boolean result = ftpClient.storeFile("upload-store.txt", bais);
		bais.close();
		assertTrue(result);

		 //方式二
		ftpClient.deleteFile("upload-store2.txt");
		OutputStream ops = ftpClient.storeFileStream("upload-store2.txt");
		ops.write(new String("中文").getBytes("GBK"));
		ops.flush();
		ops.close();

		assertEquals(new Integer(1), new Integer(reConnectFtpClient().listFiles("upload-store2.txt").length));

	}

	/**
	 * 上传excel,图片这类文件,要设置FileType为FTPClient. BINARY_FILE_TYPE 否则文件损坏
	 */
	@Test
	public void testStoreBinaryFile() throws Exception {
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

		InputStream ips = this.getClass().getClassLoader().getResourceAsStream("upload/rober.c.martin.jpg");
		assertNotNull(ips);

		//上传图片
		boolean result = ftpClient.storeFile("rober.c.martin.jpg", ips);
		assertTrue(result);
		ips.close();

		ips = this.getClass().getClassLoader().getResourceAsStream("upload/excel.xlsx");
		assertNotNull(ips);

		 // 上传excel , 可以通过转换跟创建dir方法,直接指定上传的目录
		assertEquals("/", ftpClient.printWorkingDirectory());
		ftpClient.makeDirectory("excel");
		ftpClient.changeWorkingDirectory("excel");

		result = ftpClient.storeFile("excel.xlsx", ips);
		assertTrue(result);
		ips.close();
	}

	@Test
	public void testUploadZhNameFile() throws Exception {

		ftpClient.setCharset(Charset.forName("utf-8"));

		ByteArrayInputStream bais = new ByteArrayInputStream(new String("中文").getBytes());

		boolean result = ftpClient.storeFile(new String("测试中文名.txt".getBytes(), "iso8859-1"), bais);
		assertTrue(result);

		FTPFile[] files = ftpClient.listFiles(new String("测试中文名.txt".getBytes(), "iso8859-1"));
		assertEquals(new Integer(1), new Integer(files.length));

		ftpClient.deleteFile(new String("测试中文名.txt".getBytes(), "iso8859-1"));
	}

	/**
	 * 下载文件
	 */
	@Test
	public void testRetrieveFile() throws Exception {
		String text = "text";

		boolean result = ftpClient.storeFile("upload-store.txt", new ByteArrayInputStream(new String(text).getBytes()));
		assertTrue(result);

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		result = ftpClient.retrieveFile("upload-store.txt", baos);
		assertTrue(result);

		assertEquals(text, new String(baos.toByteArray()));
		baos.close();

		//方式二
		OutputStream ops = ftpClient.storeFileStream("upload-store.txt");
		byte[] bytes = new byte[text.length()];
		ops.write(bytes);
		ops.flush();
		ops.close();
		assertEquals(text, new String(text));
	}

	/**
	 * 删除服务器文件
	 */
	@Test
	public void testDeleteFile() throws Exception {

		boolean result = ftpClient.storeFile("upload-store.txt", new ByteArrayInputStream(new String("text").getBytes()));

		 //上传成功
		assertTrue(result);

		result = ftpClient.deleteFile("upload-store.txt");

		// 判断删除成功
		assertTrue(result);
	}

	/**
	 * 目录间跳转
	 */
	@Test
	public void testDirApi() throws Exception {
		boolean result;

		assertEquals("/", ftpClient.printWorkingDirectory());

		 //返回boolean 值,如果已经存在 ,getReplyCode为550码,并返回false值
		ftpClient.makeDirectory("test-dir-1");
		ftpClient.makeDirectory("test-dir-1/test-dir-11");

		 // 如果test-dir-2这一层目录没有,不能一次创建几层的目录
		result = ftpClient.makeDirectory("test-dir-2/test-dir-2");
		assertFalse(result);

		 // changeWorkingDirectory 有相应目录返回true,无相应目录返回false
		result = ftpClient.changeWorkingDirectory("test-dir-1");
		assertTrue(result);
		assertEquals("/test-dir-1", ftpClient.printWorkingDirectory());

		result = ftpClient.changeWorkingDirectory("invalid-dir");
		assertFalse(result);

		 // 返回上一级
		ftpClient.changeToParentDirectory();
		assertEquals("/", ftpClient.printWorkingDirectory());

		 // 删除一个目录 ,如果有子目录或有子文件,则删除不成功,需要递归删除
		result = ftpClient.makeDirectory("test-remove-dir");
		assertTrue(result);
		result = ftpClient.removeDirectory("test-remove-dir");
		assertTrue(result);
	}

	@Test
	public void testListFiles() throws Exception {
		ftpClient.storeFile("test-list-files.txt", new ByteArrayInputStream("恒拓开源".getBytes()));

		FTPFile[] ftpFiles = ftpClient.listFiles();
		assertTrue(ftpFiles.length > 0);

		for (FTPFile each : ftpFiles) {
			System.out.println("######################################");
			System.out.println(each.getUser());
			System.out.println(each.getGroup());
			System.out.println(each.getLink());
			System.out.println(each.getRawListing());
			System.out.println("isFile : " + each.isFile());
			System.out.println("type : " + each.getType());
			System.out.println("######################################");
		}

		ftpClient.makeDirectory("test-list-file-dir");
		ftpClient.storeFile("test-list-file-dir/list.txt", new ByteArrayInputStream("fuck".getBytes()));

		//list 传入一个参数,指定 list改目录
		ftpFiles = ftpClient.listFiles("test-list-file-dir");
		assertEquals(new Integer(1), new Integer(ftpFiles.length));

		 // 清场工作
		ftpClient.deleteFile("test-list-files.txt");
		ftpClient.deleteFile("test-list-file-dir/list.txt");
		ftpClient.removeDirectory("test-list-file-dir");
	}

	/**
	 * 测试limit一个大小
	 */
	@Test
	public void testListFilesLimitSize() throws Exception {

		ftpClient.makeDirectory("test-list-files-limit");
		ftpClient.storeFile("test-list-files-limit/test-list-files-limit-size-1.txt", new ByteArrayInputStream("恒拓开源".getBytes()));
		ftpClient.storeFile("test-list-files-limit/test-list-files-limit-size-2.txt", new ByteArrayInputStream("恒拓开源".getBytes()));
		ftpClient.storeFile("test-list-files-limit/test-list-files-limit-size-3.txt", new ByteArrayInputStream("恒拓开源".getBytes()));

		FTPListParseEngine engine = ftpClient.initiateListParsing("test-list-files-limit");
		FTPFile[] files = engine.getNext(2);
		assertEquals(new Integer(2), new Integer(files.length));

		files = engine.getNext(1);
		assertEquals(new Integer(1), new Integer(files.length));

		ftpClient.deleteFile("test-list-files-limit/test-list-files-limit-size-1.txt");
		ftpClient.deleteFile("test-list-files-limit/test-list-files-limit-size-2.txt");
		ftpClient.deleteFile("test-list-files-limit/test-list-files-limit-size-3.txt");
		ftpClient.removeDirectory("test-list-files-limit");
	}

}
通过阅读API,有个Util类跟CopyStreamListener类结合可以在上传下载流传输的时候对字节流进行回调监控。同样做一个测试


src/test/java/com/fengzidm/spike/ftp/TestCopyStreamListener.java


package com.fengzidm.spike.ftp;

import static org.junit.Assert.*;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;
import org.apache.commons.net.io.Util;
import org.junit.After;
import org.junit.Test;

/**
 * 通过CopyStreamListener,可以有事件监听目标流读书的大小
 */
public class TestCopyStreamListener extends FtpClientTestCase
{

	private CopyStreamListener listener;

	private String FILE_PATH = "test-copy-stream-listener-upload.txt";

	@Override
	public void setUp() throws Exception
	{
		super.setUp();

		listener = new CopyStreamListener()
		{
			@Override
			public void bytesTransferred( long totalBytesTransferred, int bytesTransferred, long streamSize )
			{
				System.out.println( "#############################" );
				System.out.println( "totalBytesTransferred:" + totalBytesTransferred );
				System.out.println( "bytesTransferred:" + bytesTransferred );
				System.out.println( "streamSize:" + streamSize );
				System.out.println( "#############################" );
			}

			@Override
			public void bytesTransferred( CopyStreamEvent event )
			{
				System.out.println( "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" );
				System.out.println( "getBytesTransferred:" + event.getBytesTransferred() );
				System.out.println( "getStreamSize:" + event.getStreamSize() );
				System.out.println( "getTotalBytesTransferred:" + event.getTotalBytesTransferred() );
				System.out.println( "getSource:" + event.getSource() );
				System.out.println( "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" );
			}
		};

	}

	/**
	 * 上传文件
	 */
	@Test
	public void testStoreFile() throws Exception
	{
		String text = "恒拓开源";
		ByteArrayInputStream bais = new ByteArrayInputStream( new String( text ).getBytes() );
		OutputStream ops = ftpClient.storeFileStream( FILE_PATH );
		Long len = Util.copyStream( bais, ops, 2, text.getBytes().length, listener, true );
		
		// 一定要close
		ops.close();
		bais.close();

		assertEquals( new Long( text.getBytes().length ), len );

	}

	@Test
	public void testRetriveFile() throws Exception
	{
		String text = "恒拓开源";
		ftpClient.storeFile( FILE_PATH, new ByteArrayInputStream( text.getBytes() ) );

		InputStream ips = ftpClient.retrieveFileStream( FILE_PATH );
		BufferedOutputStream bops = new BufferedOutputStream( new ByteArrayOutputStream() );
		Long len = Util.copyStream( ips, bops, 5, text.getBytes().length, listener );
		
		bops.close();
		ips.close();
		
		assertEquals( new Long( text.getBytes().length ), len );
	}

	@After
	public void tearDown() throws Exception
	{
		ftpClient.deleteFile( FILE_PATH );

		super.tearDown();
	}

}
然后个人总结简单列举一下API



FTPClient

连接

void connect(String hostname,int port)  

关闭连接

void disconnect()

进行登录

boolean login(String username, String password)

退出登录

boolean logout()

设置超时

void setConnectTimeout()

设置命令编码

void setControlEncoding(String encoding); 

上传文件,如果文件已经存在,追加文件内容

boolean appendFile(String remote, InputStream local)

OutputStream appendFileStream(String remote)

上传文件,如果文件已经存在,重新覆盖其内容

boolean storeFile(String remote, InputStream local)

OutputStream storeFileStream(String remote)

删除文件

boolean deleteFile(String pathname)

下载文件

boolean retrieveFile(String remote, OutputStream local)

InputStream   retrieveFileStream(String remote)

重命名(移动)文件

boolean rename(String from, String to)

文件列表

FTPFile[] listFiles()

FTPFile[] listFiles(String pathname)

FTPFile[] listFiles(String pathname, FTPFileFilter filter)

目录列表

FTPFile[] listDirectories()

FTPFile[] listDirectories(String parent)

创建目录

boolean makeDirectory(String pathname)

删除目录(弱有子目录或文件,执行返回false,需递归删除)

boolean removeDirectory(String pathname)

获取当前工作目录

String printWorkingDirectory()

改变工作目录

boolean changeToParentDirectory()

boolean changeWorkingDirectory(String pathname)

设置文件类型 默认为ASCII 上传图片excel等要设置Binary类型

boolean setFileType(int fileType)

设置为主动工作模式

void enterLocalActiveMode()

设置为被动工作模式

void enterLocalPassiveMode()

获得响应码

int   getReplyCode()

获得响应信息

String     getReplyString()

String[] getReplyStrings()

 

 

FTPClientConfig

//设置服务端语言(“zh,da,fr这些”)

void  setServerLanguageCode(String serverLanguageCode)

//设置日期转换格式

void  setRecentDateFormatStr(String recentDateFormatStr)

void  setDefaultDateFormatStr(String defaultDateFormatStr)

FTPClient f=FTPClient();

   FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);

   conf.setServerLanguageCode("fr");

   f.configure(conf);

 

FTPListParseEngine 用于list**操作时可以指定如分页大小之类信息

FTPClient f=FTPClient();

    f.connect(server);

    f.login(username, password);

    FTPListParseEngine engine = f.initiateListParsing(directory);

 

    while (engine.hasNext()) {

       FTPFile[] files = engine.getNext(25);  // "page size" you want

       //do whatever you want with these files, display them, etc.

       //expensive FTPFile objects not created until needed.

    }


最后:

这里使用到只是简单FTPClient , 在commons.net.ftp包中,还有像FTPHTTPClient , FTPSClient , 这些类大家应该琢磨一下都知道是干麻用的啦^-^。




© 著作权归作者所有

XzhiF
粉丝 25
博文 28
码字总数 20041
作品 0
韶关
程序员
私信 提问
加载中

评论(9)

Mybrc91
Mybrc91
貌似是FTPClient有问题,折腾一晚上,我用ftp4j很顺利的解决了
Mybrc91
Mybrc91
list*还是有问题,有时候有起作用,有时候没用啊
XzhiF
XzhiF 博主
你的操作系统是什么,config那个有设置么?还有你listfiles的时候,当前的ftp工作目录是什么?
Mybrc91
Mybrc91
list*起作用,length方法总得到0,奇怪
Mybrc91
Mybrc91
为什么listFiles()不起作用?
Mybrc91
Mybrc91

引用来自“XzhiF”的评论

引用来自“Mybrc91”的评论

myuser.properties配置文件名字写错了,代码里是myusers.properties多了一个s

谢谢!代码里还有点错,明天回去修改下

我的需要与spring整合,研究一下
XzhiF
XzhiF 博主

引用来自“Mybrc91”的评论

myuser.properties配置文件名字写错了,代码里是myusers.properties多了一个s

谢谢!代码里还有点错,明天回去修改下
Mybrc91
Mybrc91
我也正好要做这个,学习一下
Mybrc91
Mybrc91
myuser.properties配置文件名字写错了,代码里是myusers.properties多了一个s
使用commons-pool2实现FTP连接池

一. 连接池概述 频繁的建立和关闭连接,会极大的降低系统的性能,而连接池会在初始化的时候会创建一定数量的连接,每次访问只需从连接池里获取连接,使用完毕后再放回连接池,并不是直接关闭连...

瞿落
2018/06/23
0
0
解决:Could not parse response code.Server Reply: SSH-2.0-OpenSSH_5.3

标签:change tor all pos ket server .get etc depend [摘要:办理:org.apache.commons.net.MalformedServerReplyException: Could not parse response code.Server Reply: SSH-2.0-OpenSS......

sun是我孙子
2016/12/27
2.8K
0
ftp下载文件文件名乱码问题

package mine.backstage.cms.test; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat......

美少女壮士喵
2017/11/15
2
0
Apache Commons 常用工具包

Apache Commons是一个非常有用的工具包,解决各种实际的通用问题,下面是一个简述表,详细信息访问http://jakarta.apache.org/commons/index.html BeanUtils Commons-BeanUtils 提供对 Java...

K_ONE
2016/05/04
207
0
java jar包收集

activation~与javaMail有关的jar包,使用javaMail时应与mail.jar (mail.jar和activation.jar)一起加入到lib中去,具体负责mail的数据源和类型等。 ApacheActiveMQ~Apache出品,最流行的,能力...

文艺小青年
2017/07/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

单例的创建以及常见的几种实现模式

单例是用来干嘛的? 1.一种设计模式, 2.一般都是资源类,如数据库连接池等, 3.但是要保证一个类仅有一个实例,并提供一个访问它的全局访问点。(只能提供私有的构造器,即保证不能随意创建该...

费先森
32分钟前
27
0
【Seata微服务分布式事务】2. Seata微服务分布式事务项目搭建

引依赖 <!--seata--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><exclusions><exclusion>......

贺小康
42分钟前
13
0
这四个问题场景你会排查原因吗?看看高手是如何使用 Arthas 快速定位原因的!

作者 | [张奇(司楚)] 当线上碰到头疼的问题时,还在对着代码一行行的看?真的不太时髦了啊喂~ 俗话说的好 “问题排查不用愁,Arthas 来帮您忙。” 今天就来说说这个让妈妈再也不用担心我排查...

阿里巴巴云原生
42分钟前
26
0
创龙TI TMS320C6748(定点/浮点DSP C674x)的SATA硬盘接口、RJ45以太网口

TMS320C6748 TI TMS320C6748是一款低功耗浮点DSP处理器。支持DSP的高数字信号处理性能和精简指令计算机(RISC)技术,采用一个高性能的456MHz TMS320C674x 32位处理器。以下是TMS320C6748 C...

Tronlong创龙
44分钟前
23
0
mp3格式转换器怎么用?这有高效转换音频格式的方法

mp3格式转换器怎么用?mp3格式是众多音频格式中的其中一种,相比于其他m4a、ogg和aac等格式是更为常见的一种。也正因此mp3有更加高的兼容性,所以很多小伙伴获得别的音频文件时会选择第一时间...

cenfeng123
44分钟前
22
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部