最近在做ssh ,sftp。顺便总结一下java实现ftp的几种方式。

1、sun.net

import sun.net.ftp.*;

import sun.net.*;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.ByteArrayOutputStream;

import java.util.ArrayList;

import java.util.StringTokenizer;

/**

FTP远程命令列表

USER    PORT    RETR    ALLO    DELE    SITE    XMKD    CDUP    FEAT

PASS    PASV    STOR    REST    CWD     STAT    RMD     XCUP    OPTS

ACCT    TYPE    APPE    RNFR    XCWD    HELP    XRMD    STOU    AUTH

REIN    STRU    SMNT    RNTO    LIST    NOOP    PWD     SIZE    PBSZ

QUIT    MODE    SYST    ABOR    NLST    MKD     XPWD    MDTM    PROT

在服务器上执行命令,如果用sendServer来执行远程命令(不能执行本地FTP命令)的话,所有FTP命令都要加上\r\n

ftpclient.sendServer("XMKD /test/bb\r\n"); //执行服务器上的FTP命令

ftpclient.readServerResponse一定要在sendServer后调用

nameList("/test")获取指目录下的文件列表

XMKD建立目录,当目录存在的情况下再次创建目录时报错

XRMD删除目录

DELE删除文件

*

Title: 使用JAVA操作FTP服务器(FTP客户端)

*

Description: 上传文件的类型及文件大小都放到调用此类的方法中去检测,比如放到前台JAVASCRIPT中去检测等

* 针对FTP中的所有调用使用到文件名的地方请使用完整的路径名(绝对路径开始)。

*

*

Copyright: Copyright (c) 2005

*

Company: 静靖工作室

* @author 欧朝敬  13873195792

* @version 1.0

*/

public class FtpUpfile {

private FtpClient ftpclient;

private String ipAddress;

private int ipPort;

private String userName;

private String PassWord;

/**

* 构造函数

* @param ip String 机器IP

* @param port String 机器FTP端口号

* @param username String FTP用户名

* @param password String FTP密码

* @throws Exception

*/

public FtpUpfile(String ip, int port, String username, String password) throws

Exception {

ipAddress = new String(ip);

ipPort = port;

ftpclient = new FtpClient(ipAddress, ipPort);

//ftpclient = new FtpClient(ipAddress);

userName = new String(username);

PassWord = new String(password);

}

/**

* 构造函数

* @param ip String 机器IP,默认端口为21

* @param username String FTP用户名

* @param password String FTP密码

* @throws Exception

*/

public FtpUpfile(String ip, String username, String password) throws

Exception {

ipAddress = new String(ip);

ipPort = 21;

ftpclient = new FtpClient(ipAddress, ipPort);

//ftpclient = new FtpClient(ipAddress);

userName = new String(username);

PassWord = new String(password);

}

/**

* 登录FTP服务器

* @throws Exception

*/

public void login() throws Exception {

ftpclient.login(userName, PassWord);

}

/**

* 退出FTP服务器

* @throws Exception

*/

public void logout() throws Exception {

//用ftpclient.closeServer()断开FTP出错时用下更语句退出

ftpclient.sendServer("QUIT\r\n");

int reply = ftpclient.readServerResponse(); //取得服务器的返回信息

}

/**

* 在FTP服务器上建立指定的目录,当目录已经存在的情下不会影响目录下的文件,这样用以判断FTP

* 上传文件时保证目录的存在目录格式必须以"/"根目录开头

* @param pathList String

* @throws Exception

*/

public void buildList(String pathList) throws Exception {

ftpclient.ascii();

StringTokenizer s = new StringTokenizer(pathList, "/"); //sign

int count = s.countTokens();

String pathName = "";

while (s.hasMoreElements()) {

pathName = pathName + "/" + (String) s.nextElement();

try {

ftpclient.sendServer("XMKD " + pathName + "\r\n");

} catch (Exception e) {

e = null;

}

int reply = ftpclient.readServerResponse();

}

ftpclient.binary();

}

/**

* 取得指定目录下的所有文件名,不包括目录名称

* 分析nameList得到的输入流中的数,得到指定目录下的所有文件名

* @param fullPath String

* @return ArrayList

* @throws Exception

*/

public ArrayList fileNames(String fullPath) throws Exception {

ftpclient.ascii(); //注意,使用字符模式

TelnetInputStream list = ftpclient.nameList(fullPath);

byte[] names = new byte[2048];

int bufsize = 0;

bufsize = list.read(names, 0, names.length); //从流中读取

list.close();

ArrayList namesList = new ArrayList();

int i = 0;

int j = 0;

while (i < bufsize /*names.length*/) {

//char bc = (char) names;

//System.out.println(i + "  " + bc + " : " + (int) names);

//i = i + 1;

if (names[i] == 10) { //字符模式为10,二进制模式为13

//文件名在数据中开始下标为j,i-j为文件名的长度,文件名在数据中的结束下标为i-1

//System.out.write(names, j, i - j);

//System.out.println(j + "   " + i + "    " + (i - j));

String tempName = new String(names, j, i - j);

namesList.add(tempName);

//System.out.println(temp);

// 处理代码处

//j = i + 2; //上一次位置二进制模式

j = i + 1; //上一次位置字符模式

}

i = i + 1;

}

return namesList;

}

/**

* 上传文件到FTP服务器,destination路径以FTP服务器的"/"开始,带文件名、

* 上传文件只能使用二进制模式,当文件存在时再次上传则会覆盖

* @param source String

* @param destination String

* @throws Exception

*/

public void upFile(String source, String destination) throws Exception {

buildList(destination.substring(0, destination.lastIndexOf("/")));

ftpclient.binary(); //此行代码必须放在buildList之后

TelnetOutputStream ftpOut = ftpclient.put(destination);

TelnetInputStream ftpIn = new TelnetInputStream(new

FileInputStream(source), true);

byte[] buf = new byte[204800];

int bufsize = 0;

while ((bufsize = ftpIn.read(buf, 0, buf.length)) != -1) {

ftpOut.write(buf, 0, bufsize);

}

ftpIn.close();

ftpOut.close();

}

/**

* JSP中的流上传到FTP服务器,

* 上传文件只能使用二进制模式,当文件存在时再次上传则会覆盖

* 字节数组做为文件的输入流,此方法适用于JSP中通过

* request输入流来直接上传文件在RequestUpload类中调用了此方法,

* destination路径以FTP服务器的"/"开始,带文件名

* @param sourceData byte[]

* @param destination String

* @throws Exception

*/

public void upFile(byte[] sourceData, String destination) throws Exception {

buildList(destination.substring(0, destination.lastIndexOf("/")));

ftpclient.binary(); //此行代码必须放在buildList之后

TelnetOutputStream ftpOut = ftpclient.put(destination);

ftpOut.write(sourceData, 0, sourceData.length);

//        ftpOut.flush();

ftpOut.close();

}

/**

* 从FTP文件服务器上下载文件SourceFileName,到本地destinationFileName

* 所有的文件名中都要求包括完整的路径名在内

* @param SourceFileName String

* @param destinationFileName String

* @throws Exception

*/

public void downFile(String SourceFileName, String destinationFileName) throws

Exception {

ftpclient.binary(); //一定要使用二进制模式

TelnetInputStream ftpIn = ftpclient.get(SourceFileName);

byte[] buf = new byte[204800];

int bufsize = 0;

FileOutputStream ftpOut = new FileOutputStream(destinationFileName);

while ((bufsize = ftpIn.read(buf, 0, buf.length)) != -1) {

ftpOut.write(buf, 0, bufsize);

}

ftpOut.close();

ftpIn.close();

}

/**

*从FTP文件服务器上下载文件,输出到字节数组中

* @param SourceFileName String

* @return byte[]

* @throws Exception

*/

public byte[] downFile(String SourceFileName) throws

Exception {

ftpclient.binary(); //一定要使用二进制模式

TelnetInputStream ftpIn = ftpclient.get(SourceFileName);

ByteArrayOutputStream byteOut = new ByteArrayOutputStream();

byte[] buf = new byte[204800];

int bufsize = 0;

while ((bufsize = ftpIn.read(buf, 0, buf.length)) != -1) {

byteOut.write(buf, 0, bufsize);

}

byte[] return_arraybyte = byteOut.toByteArray();

byteOut.close();

ftpIn.close();

return return_arraybyte;

}

/**调用示例

* FtpUpfile fUp = new FtpUpfile("192.150.189.22", 21, "admin", "admin");

* fUp.login();

* fUp.buildList("/adfadsg/sfsdfd/cc");

* String destination = "/test.zip";

* fUp.upFile("C:\\Documents and Settings\\Administrator\\My Documents\\sample.zip",destination);

* ArrayList filename = fUp.fileNames("/");

* for (int i = 0; i < filename.size(); i++) {

*     System.out.println(filename.get(i).toString());

* }

* fUp.logout();

* @param args String[]

* @throws Exception

*/

public static void main(String[] args) throws Exception {

FtpUpfile fUp = new FtpUpfile("172.16.0.142", 22, "ivr", "ivr");

fUp.login();

/*        fUp.buildList("/adfadsg/sfsdfd/cc");

String destination = "/test/SetupDJ.rar";

fUp.upFile(

"C:\\Documents and Settings\\Administrator\\My Documents\\SetupDJ.rar",

destination);

ArrayList filename = fUp.fileNames("/");

for (int i = 0; i < filename.size(); i++) {

System.out.println(filename.get(i).toString());

}

fUp.downFile("/sample.zip", "d:\\sample.zip");

*/

FileInputStream fin = new FileInputStream(

"d:\\wapPush.txt");

byte[] data = new byte[20480000];

fin.read(data, 0, data.length);

fUp.upFile(data, "/home/cdr/wapPush.txt");

fUp.logout();

System.out.println("程序运行完成!");

/*FTP远程命令列表

USER    PORT    RETR    ALLO    DELE    SITE    XMKD    CDUP    FEAT

PASS    PASV    STOR    REST    CWD     STAT    RMD     XCUP    OPTS

ACCT    TYPE    APPE    RNFR    XCWD    HELP    XRMD    STOU    AUTH

REIN    STRU    SMNT    RNTO    LIST    NOOP    PWD     SIZE    PBSZ

QUIT    MODE    SYST    ABOR    NLST    MKD     XPWD    MDTM    PROT

*/

/*在服务器上执行命令,如果用sendServer来执行远程命令(不能执行本地FTP命令)的话,所有FTP命令都要加上\r\n

ftpclient.sendServer("XMKD /test/bb\r\n"); //执行服务器上的FTP命令

ftpclient.readServerResponse一定要在sendServer后调用

nameList("/test")获取指目录下的文件列表

XMKD建立目录,当目录存在的情况下再次创建目录时报错

XRMD删除目录

DELE删除文件

*/

}

}

2、apache的common.net

package com.ftp;

import java.io.*;

import java.net.InetAddress;

import org.apache.commons.net.ftp.*;

import org.apache.commons.net.ftp.parser.*;

import org.apache.commons.net.ftp.FTPFile;

import org.apache.commons.net.ftp.FTPFileEntryParser;

import sun.net.TelnetInputStream;

public class FtpAppache {

public FtpAppache() throws Exception{

// sun.net.ftp.FtpClient ft = null;

//  TelnetInputStream t = ft.list();

// t.setStickyCRLF(true);

}

public void test1() throws Exception {

//

String strTemp = "";

//InetAddress ia = InetAddress.getByName("192.168.0.193");

FTPClient ftp = new FTPClient();

ftp.connect("172.16.0.142",22

);

boolean blogin =

ftp.login("ivr

", "ivr");

if (!blogin) {

System.out.println("连接失败");

ftp.disconnect

();

ftp = null;

return;

}

/*//如果是中文名必需进行字符集转换

boolean bMakeFlag =

ftp.makeDirectory(new

String("测试目录".getBytes(

"gb2312"), "iso-8859-1")); //在服务器创建目录

//上传文件到服务器,目录自由创建

File file = new File("c:\\test.properties");

ftp.storeFile("test.properties",new

FileInputStream(file));*/

System.out.println(

ftp.getSystemName

());

FTPFile[] ftpFiles =

ftp.listFiles

();

if (ftpFiles != null) {

for (int i = 0; i < ftpFiles.length; i++) {

System.out.println(ftpFiles[i].getName());

//System.out.println(ftpFiles[i].isFile());

if (ftpFiles[i].isFile()) {

FTPFile ftpf = new FTPFile();

/*System.err.println(ftpf.hasPermission(FTPFile.GROUP_ACCESS,

FTPFile.EXECUTE_PERMISSION));

System.err.println("READ_PERMISSION="+ftpf.hasPermission(FTPFile.USER_ACCESS,

FTPFile.READ_PERMISSION));

System.err.println("EXECUTE_PERMISSION="+ftpf.hasPermission(FTPFile.USER_ACCESS,

FTPFile.EXECUTE_PERMISSION));

System.err.println("WRITE_PERMISSION="+ftpf.hasPermission(FTPFile.USER_ACCESS,

FTPFile.WRITE_PERMISSION));

System.err.println(ftpf.hasPermission(FTPFile.WORLD_ACCESS,

FTPFile.READ_PERMISSION));*/

}

//System.out.println(ftpFiles[i].getUser());

}

}

//下载服务器文件

FileOutputStream fos = new FileOutputStream("e:/proftpd-1.2.10.tar.gz");

ftp.retrieveFile("proftpd-1.2.10.tar.gz",fos

);

fos.close();

//改变ftp目录

//ftp.changeToParentDirectory();//回到父目录

//ftp.changeWorkingDirectory("");//转移工作目录

//ftp.completePendingCommand();//

//删除ftp服务器文件

//ftp.deleteFile("");

//注销当前用户,

//ftp.logout();

//ftp.structureMount("");

ftp.disconnect

();

ftp = null;

}

/**

* 封装好的东西是好用,碰到这种问题,我们就。。。up

* @param args String[]

*/

public static void main(String[] args) {

try {

FtpAppache ftpAppache1 = new FtpAppache();

ftpAppache1.test1();

}

catch (Exception e) {

e.printStackTrace();

}

}

}

3、edtftpj

package com.boss;

import com.enterprisedt.net.ftp.FTPClient;

import com.enterprisedt.net.ftp.FTPMessageCollector;

import com.enterprisedt.net.ftp.FTPTransferType;

import com.enterprisedt.net.ftp.FTPConnectMode;

import com.enterprisedt.util.debug.Level;

import com.enterprisedt.util.debug.Logger;

/**

*  Simple test class for FTPClient

*

*  @author      Hans Andersen

*  @author      Bruce Blackshaw

*/

public class Demo {

/**

*  Revision control id

*/

private static String cvsId = "@(#)$Id: Demo.java,v 1.6 2005/03/18 11:12:56 bruceb Exp $";

/**

*  Log stream

*/

private static Logger log = Logger.getLogger(Demo.class);

/**

* Standard main()

*

* @param args  standard args

*/

public static void main(String[] args) {

// assign args to make it clear

String host = "172.16.0.142";

String user = "ivr";

String password = "ivr";

Logger.setLevel(Level.ALL);

FTPClient ftp = null;

try {

// set up client

ftp = new FTPClient();

ftp.setRemoteHost(host

);

ftp.setRemotePort(22

);

ftp.setConnectMode(FTPConnectMode.ACTIVE

);

FTPMessageCollector listener = new FTPMessageCollector();

ftp.setMessageListener(listener

);

//ftp.setAutoPassiveIPSubstitution(true);

// connect

log.info("Connecting");

ftp.connect

();

// login

log.info("Logging in");

ftp.login(user

, password);

// set up passive ASCII transfers

log.debug("Setting up passive, ASCII transfers");

ftp.setConnectMode(FTPConnectMode.PASV

);

ftp.setType(FTPTransferType.ASCII

);

// get directory and print it to console

log.debug("Directory before put:");

String[] files =

ftp.dir

(".", true);

for (int i = 0; i < files.length; i++)

log.debug(files[i]);

// copy file to server

log.info("Putting file");

ftp.put("test.txt

", "test.txt");

// get directory and print it to console

log.debug("Directory after put");

files =

ftp.dir

(".", true);

for (int i = 0; i < files.length; i++)

log.debug(files[i]);

// copy file from server

log.info("Getting file");

ftp.get("test.txt

" + ".copy", "test.txt");

// delete file from server

log.info("Deleting file");

ftp.delete("test.txt

");

// get directory and print it to console

log.debug("Directory after delete");

files =

ftp.dir

("", true);

for (int i = 0; i < files.length; i++)

log.debug(files[i]);

// Shut down client

log.info("Quitting client");

ftp.quit

();

String messages = listener.getLog();

log.debug("Listener log:");

log.debug(messages);

log.info("Test complete");

} catch (Exception e) {

log.error("Demo failed", e);

}

}

/**

*  Basic usage statement

*/

public static void usage() {

System.out.println("Usage: Demo remotehost user password");

}

}

4、sshtools,maverick-ssh.jar

package com.sshtools.examples.echo;

import com.sshtools.j2ssh.configuration.SshConnectionProperties;

import com.sshtools.j2ssh.authentication.*;

import com.sshtools.j2ssh.transport.*;

import com.sshtools.j2ssh.SshException;

import org.apache.log4j.Logger;

import java.io.*;

import com.sshtools.j2ssh.subsystem.*;

/**

*

*

Echo Client

*

Provides a simple example of using the sshtools subsystem framework

*

Copyright: Copyright (c) 2002 Lee David Painter

*

Company: Sshtools.com

* @author Lee David Painter

* @version 1.0

*/

public class EchoClient extends SubsystemClient {

private static Logger log = Logger.getLogger(EchoClient.class);

/**

* Contructor for the echo client object

*/

public EchoClient() {

super("echo", true);

registerSubsystemMessage(EchoMessage.SSH_ECHO_MESSAGE, EchoMessage.class);

}

/**

* Sends a string to the remote ssh server and waits for the same string

* to be echoed back

* @param msg

*/

public void sendEcho(String msg) {

try {

EchoMessage echo = new EchoMessage(msg);

this.sendMessage(echo);

SubsystemMessage reply = nextMessage();

if(reply.getMessageType()== EchoMessage.SSH_ECHO_MESSAGE) {

System.out.println("Server echo> " + ((EchoMessage)reply).getMessage());

}

}

catch(SshException e) {

e.printStackTrace();

}

}

/**

* Entry point for the EchoClient sample application

* @param args

*/

public static void main(String args[]) {

try {

org.apache.log4j.BasicConfigurator.configure();

EchoClient client = new EchoClient();

SshConnectionProperties properties = new SshConnectionProperties();

properties.setHost("172.106.0.142");

properties.setUsername("ivr");

final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

client.connect(properties, new HostKeyVerification() {

public void onDeniedHost(String host) {

System.out.println("Access to the host " + host + " is denied from this system");

}

public void onHostKeyMismatch(String host, String fingerprint, String actual) {

try {

System.out.println("The host key supplied by " + host + " is: " + actual);

System.out.println("The current allowed key for " + host + " is: " + fingerprint);

getResponse(host, actual);

}

catch(Exception e) {

e.printStackTrace();

}

}

private void getResponse(String host, String fingerprint)

throws InvalidHostFileException,

IOException {

String response = "";

while(!(response.equalsIgnoreCase("YES") || response.equalsIgnoreCase("NO")

|| response.equalsIgnoreCase("ALWAYS"))) {

System.out.print("Do you want to allow this host key? [Yes|No|Always]: ");

response = reader.readLine();

}

if(response.equalsIgnoreCase("YES"))

allowHost(host, fingerprint, false);

if(response.equalsIgnoreCase("NO")) {

System.out.println("Cannot continue without a valid host key");

System.exit(1);

}

if(response.equalsIgnoreCase("ALWAYS"))

allowHost(host, fingerprint, true);

}

public void onUnknownHost(String host, String fingerprint) {

try {

System.out.println("The host " +  host + " is currently unknown to the system");

System.out.println("The host key fingerprint is: " + fingerprint);

getResponse(host, fingerprint);

}

catch(Exception e) {

e.printStackTrace();

}

}

});

PasswordAuthentication password = new PasswordAuthentication();

password.setPassword("ivr");

password.setUsername("ivr");

client.authenticate(password);

String message;

do {

System.out.print("Message> ");

message = reader.readLine();

client.sendEcho(message);

} while(!message.equalsIgnoreCase("EXIT"));

client.close();

}

catch(SshException e) {

e.printStackTrace();

}

catch(IOException ioe) {

ioe.printStackTrace();

}

}

}

java ftp connect_java实现ftp的几种方式(第3方包)相关推荐

  1. Java异步非阻塞编程的几种方式

    简介: Java异步非阻塞编程的几种方式 一. 从一个同步的Http调用说起 一个很简单的业务逻辑,其他后端服务提供了一个接口,我们需要通过接口调用,获取到响应的数据. 逆地理接口:通过经纬度获取这个 ...

  2. 【java】Java运行时动态生成类几种方式

    1.概述 转载:Java运行时动态生成类几种方式 这里发现自己不知道的,原来Java 还能自己编译自己,学到了. 最近一个项目中利用规则引擎,提供用户拖拽式的灵活定义规则.这就要求根据数据库数据动态生 ...

  3. java的如何创建js_[Java教程]JS创建事件的三种方式(实例)

    [Java教程]JS创建事件的三种方式(实例) 0 2016-05-11 14:00:16 1.普通的定义方式 οnclick="Sfont=prompt('请在文本框中输入红色','红色' ...

  4. Java中线程的创建有两种方式

    Java中继承thread类与实现Runnable接口的区别 Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过 ...

  5. Java实现回文串的四种方式

    Java实现回文串的两种方式 1.什么是回文串? "回文串"是一个正读和反读都一样的字符串,如"level"或者"noon"等就是回文串. ...

  6. Java中遍历Map集合的5种方式总结

    这篇文章主要给大家介绍了关于Java中遍历Map集合的5种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值. 方式一 通过Map.keySet使用iterator遍历 ...

  7. 读取Java文件到byte数组的三种方式及Java文件操作大全(包括文件加密,String加密)

    读取Java文件到byte数组的三种方式 package zs;import java.io.BufferedInputStream; import java.io.ByteArrayOutputSt ...

  8. Java生成唯一标识码的三种方式

    Java生成唯一标识码的三种方式 前言 我们经常会遇到这样的场景,需要生成一个唯一的序列号来表明某一个数据的唯一性,在单节点的应用中我们可以简单地使用一个自增的整型来实现实现,但是在分布式情况下这个方 ...

  9. java的list遍历_【java】list集合遍历的5种方式

    平凡也就两个字: 懒和惰; 成功也就两个字: 苦和勤; 优秀也就两个字: 你和我. 跟着我从0学习JAVA.spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美! 关注微信 ...

  10. 用java自己实现代码阻塞的几种方式

    用java自己实现代码阻塞的几种方式 假如有一个场景,当代码获取的变量不为期待值的时候需要等待变量变为期待值再往下执行,最开始可能会考虑通过死循环+线程睡眠来实现,但是这样子毕竟不太合理.可以通过以下 ...

最新文章

  1. RAID之中的RAID5的创建及示例
  2. oracle数据连接出现 login denied 问题
  3. AD域中删除OU,提示没权限。 解决办法。
  4. cfb为什么不需要填充_学日语为什么不需要准备,现在就可以学?
  5. 今晚直播丨分布式数据库:从PG-XL到TBASE
  6. 95 后程序员一出校门就拿年薪 32 万?
  7. SAP HANA创建类型(SAP HANA CREATE TYPE):
  8. mysql并发replace死锁
  9. html 自动关机程序,Windows 自动关机/定时关机 命令 shuntdown
  10. WPF Ribbon 开发资料分享
  11. 金蝶K3对接数据库相应语句大全
  12. 反爬虫策略的应对方法汇总
  13. linux:硬链接和软链接
  14. 【破解软件】知音漫客免费看更多漫画
  15. C primer Plus 9.3.4 递归和倒序计算 DE3
  16. Linux下通过NetLink获取网口信息
  17. win10的高占用CPU的进程wsappx关闭指南+解决win10应用商店打不开
  18. Java多个文件根据URL下载后打包zip导出
  19. 安卓手机使用termux搭建centos7个人博客服务器
  20. 银行IT部门招聘笔试题

热门文章

  1. C++建立动态二维数组
  2. html frame 菜单切换,官方底部导航如何通过frame0.html的JS控制切换
  3. mysql的索引的区别_MYSQL索引区别
  4. 中文发音关系频谱的猜想
  5. python读取内存和空闲内存
  6. 神经网络版员工离职预测
  7. AUTOML 和 NAS 的真谛
  8. fork() 成为负担,需要淘汰
  9. 前端各阶段资源,学得完算我输
  10. 9月9日项目群管理活动讨论