FTP Client library in C# (轉)
FTP Client library in C# (轉)[@more@]這是個用寫的客戶端庫,可編譯成DLL使用,
支援所有的FTP命令、檔案上下傳,
/*
FTPFactory.cs
Better view with tab space=4
use the following line to compile
csc /target:library /out:FTPLib.dll /r:System.DLL FTPFactory.cs
*/
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Net.Sockets;
namespace FtpLib {
public class FTPFactory {
private string remoteHost,remotePath,remoteUser,remotePass,mes;
private int remotePort,bytes;
private Socket clientSocket;
private int retValue;
private Boolean de;
private Boolean logined;
private string reply;
private static int BLOCK_SIZE = 512;
Byte[] buffer = new Byte[BLOCK_SIZE];
Encoding ASCII = Encoding.ASCII;
public FTPFactory() {
remoteHost = "localhost";
remotePath = ".";
remoteUser = "anonymous";
remotePass = "ftpclient@ospreyindia.com";
remotePort = 21;
debug = false;
logined = false;
}
public void setRemoteHost(string remoteHost) {
this.remoteHost = remoteHost;
}
public string getRemoteHost() {
return remoteHost;
}
public void setRemotePort(int remotePort) {
this.remotePort = remotePort;
}
public int getRemotePort() {
return remotePort;
}
public void setRemotePath(string remotePath) {
this.remotePath = remotePath;
}
public string getRemotePath() {
return remotePath;
}
public void setRemoteUser(string remoteUser) {
this.remoteUser = remoteUser;
}
public void setRemotePass(string remotePass) {
this.remotePass = remotePass;
}
public string[] getFileList(string mask) {
if(!logined) {
login();
}
Socket cSocket = createDataSocket();
sendCommand("NLST " + mask);
if(!(retValue == 150 || retValue == 125)) {
throw new IOException(reply.Substring(4));
}
mes = "";
while(true) {
int bytes = cSocket.Receive(buffer, buffer.Length, 0);
mes += ASCII.GetString(buffer, 0, bytes);
if(bytes < buffer.Length) {
break;
}
}
char[] seperator = {'n'};
string[] mess = mes.Split(seperator);
cSocket.Close();
readReply();
if(retValue != 226) {
throw new IOException(reply.Substring(4));
}
return mess;
}
public long getFileSize(string fileName) {
if(!logined) {
login();
}
sendCommand("SIZE " + fileName);
long size=0;
if(retValue == 213) {
size = reply.Substring(4).ToInt64();
}else {
throw new IOException(reply.Substring(4));
}
return size;
}
public void login() {
clientSocket = new Socket(Addresamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
IPEndPoint ep = new IPEndPoint(.Resolve(remoteHost), remotePort);
int i = clientSocket.Connect(ep);
if( i != 0 ) {
throw new IOException("Couldn't connect to remote server");
}
readReply();
if(retValue != 220) {
close();
throw new IOException(reply.Substring(4));
}
if(debug)
Console.WriteLine("USER "+remoteUser);
sendCommand("USER "+remoteUser);
if( !(retValue == 331 || retValue == 230) ) {
cleanup();
throw new IOException(reply.Substring(4));
}
if( retValue != 230 ) {
if(debug)
Console.WriteLine("PASS xxx");
sendCommand("PASS "+remotePass);
if( !(retValue == 230 || retValue == 202) ) {
cleanup();
throw new IOException(reply.Substring(4));
}
}
logined = true;
Console.WriteLine("Connected to "+remoteHost);
chdir(remotePath);
}
public void setBinaryMode(Boolean mode) {
if(mode) {
sendCommand("TYPE I");
}else {
sendCommand("TYPE A");
}
if (retValue != 200) {
throw new IOException(reply.Substring(4));
}
}
public void (string fileName) {
download(fileName,false);
}
public void download(string fileName,Boolean resume) {
if(!logined) {
login();
}
setBinaryMode(true);
long totalSize=0;
try{
totalSize = getFileSize(fileName);
}catch(Exception) {
throw new Exception("File Not Found "+fileName);
}
Console.WriteLine("Downloading file "+fileName+" from "+remoteHost + "/"+remotePath);
if(!File.FileExists(fileName)) {
Stream st = File.Create(fileName);
st.Close();
}
FileStream output = new FileStream(fileName,FileMode.Open);
Socket cSocket = createDataSocket();
long offset = 0;
if(resume) {
offset = output.Length;
if(offset > 0 ) {
sendCommand("REST "+offset);
if(retValue != 350) {
//throw new IOException(reply.Substring(4));
//Server may not support resuming.
offset = 0;
}
}
if(offset > 0) {
if(debug) {
Console.WriteLine("seeking to " + offset);
}
long npos = output.Seek(offset,SeekOrigin.Begin);
Console.WriteLine("new pos="+npos);
}
}
sendCommand("RETR " + fileName);
if(!(retValue == 150 || retValue == 125)) {
throw new IOException(reply.Substring(4));
}
float iCnt = 0;
float per = 0, oldPer = 1;
while(true) {
bytes = cSocket.Receive(buffer, buffer.Length, 0);
output.Write(buffer,0,bytes);
// Showing the progress. 1..50
iCnt += bytes;
per = (int) ( (iCnt / totalSize) * 100 );
if( per != oldPer && per % 2 == 0 ) {
Console.Write(".");
oldPer = per;
}
if(bytes < buffer.Length) {
break;
}
}
output.Close();
cSocket.Close();
Console.WriteLine("");
readReply();
if( !(retValue == 226 || retValue == 250) ) {
throw new IOException(reply.Substring(4));
}
}
public void (string fileName) {
upload(fileName,false);
}
public void upload(string fileName,Boolean resume) {
if(!logined) {
login();
}
Socket cSocket = createDataSocket();
long offset=0;
if(resume) {
try {
setBinaryMode(true);
offset = getFileSize(fileName);
}catch(Exception) {
offset = 0;
}
}
if(offset > 0 ) {
sendCommand("REST " + offset);
if(retValue != 350) {
//throw new IOException(reply.Substring(4));
//Remote server may not support resuming.
offset = 0;
}
}
sendCommand("STOR "+fileName);
if( !(retValue == 125 || retValue == 150) ) {
throw new IOException(reply.Substring(4));
}
// open input stream to read file
FileStream input = new FileStream(fileName,FileMode.Open);
if(offset != 0){
if(debug) {
Console.WriteLine("seeking to " + offset);
}
input.Seek(offset,SeekOrigin.Begin);
}
//for progress bar
long totalSize = input.Length - offset;
float iCnt = 0;
int per = 0, oldPer = 1;
Console.WriteLine("Uploading file "+fileName+" to "+remotePath);
while ((bytes = input.Read(buffer,0,buffer.Length)) > 0) {
cSocket.Send(buffer, bytes, 0);
// Showing the progress. 1..50
iCnt += bytes;
per = (int) ( (iCnt / totalSize) * 100 );
if( per != oldPer && per % 2 == 0 ) {
Console.Write(".");
oldPer = per;
}
}
input.Close();
Console.WriteLine("");
cSocket.Close();
readReply();
if( !(retValue == 226 || retValue == 250) ) {
throw new IOException(reply.Substring(4));
}
}
public void deleteRemoteFile(string fileName) {
if(!logined) {
login();
}
sendCommand("DELE "+fileName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void renameRemoteFile(string oldFileName,string newFileName) {
if(!logined) {
login();
}
sendCommand("RNFR "+oldFileName);
if(retValue != 350) {
throw new IOException(reply.Substring(4));
}
// known problem
// rnto will not take care of existing file.
// i.e. It will overwrite if newFileName exist
sendCommand("RNTO "+newFileName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void mkdir(string dirName) {
if(!logined) {
login();
}
sendCommand("MKD "+dirName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void rmdir(string dirName) {
if(!logined) {
login();
}
sendCommand("RMD "+dirName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void chdir(string dirName) {
if(dirName.Equals(".")) {
return;
}
if(!logined) {
login();
}
sendCommand("CWD "+dirName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
this.remotePath = dirName;
Console.WriteLine("Current directory is "+remotePath);
}
public void close() {
if( clientSocket != null ) {
sendCommand("QUIT");
}
cleanup();
Console.WriteLine("Closing...");
}
public void setDebug(Boolean debug) {
this.debug = debug;
}
private void readReply() {
mes = "";
reply = readLine();
retValue = reply.Substring(0,3).ToInt32();
}
private void cleanup() {
if(clientSocket!=null) {
clientSocket.Close();
clientSocket = null;
}
logined = false;
}
private string readLine() {
while(true) {
bytes = clientSocket.Receive(buffer, buffer.Length, 0);
mes += ASCII.GetString(buffer, 0, bytes);
if(bytes < buffer.Length) {
break;
}
}
char[] seperator = {'n'};
string[] mess = mes.Split(seperator);
if(mes.Length > 2) {
mes = mess[mess.Length-2];
}else {
mes = mess[0];
}
if(!mes.Substring(3,1).Equals(" ")) {
return readLine();
}
if(debug) {
for(int k=0;k < mess.Length-1;k++) {
Console.WriteLine(mess[k]);
}
}
return mes;
}
private void sendCommand(String command) {
Byte[] cmytes = Encoding.ASCII.GetBytes((command+"rn").ToCharArray());
clientSocket.Send(cmdBytes, cmdBytes.Length, 0);
readReply();
}
private Socket createDataSocket() {
sendCommand("PASV");
if(retValue != 227) {
throw new IOException(reply.Substring(4));
}
int index1 = reply.IndexOf('(');
int index2 = reply.IndexOf(')');
string ipData = reply.Substring(index1+1,index2-index1-1);
int[] parts = new int[6];
int len = ipData.Length;
int partCount = 0;
string buf="";
for (int i = 0; i < len && partCount <= 6; i++) {
char ch = ipData.Substring(i,1).ToChar();
if (Char.IsDigit(ch))
buf+=ch;
else if (ch != ',') {
throw new IOException("Malformed PASV reply: " + reply);
}
if (ch == ',' || i+1 == len) {
try {
parts[partCount++] = buf.ToInt32();
buf="";
}
catch (Exception) {
throw new IOException("Malformed PASV reply: " + reply);
}
}
}
string ipAddress = parts[0] + "."+ parts[1]+ "." +
parts[2] + "." + parts[3];
int port = (parts[4] << 8) + parts[5];
Socket s = new Socket(AddressFamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
IPEndPoint ep = new IPEndPoint(DNS.Resolve(ipAddress), port);
int sucess = s.Connect(ep);
if( sucess != 0 ) {
throw new IOException("Can't connect to remote server");
}
return s;
}
}
}
Following is the listing of a test program which uses this library
/*
File : Test.cs
Better view with tab space=4
use the following line to compile
csc.exe /t:exe /r:System.DLL /r:System.Net.DLL /r:FTPLib.dll /out:"Test.exe" "Test.cs"
*/
using System;
using FtpLib;
public class Test {
public static void Main() {
try {
Console.WriteLine("Starting...");
FTPFactory ff = new FTPFactory();
ff.setDebug(true);
ff.setRemoteHost("192.168.10.19");
ff.setRemoteUser("jaimon");
ff.setRemotePass("mathew");
ff.login();
string[] fileNames = ff.getFileList("*.*");
for(int i=0;i < fileNames.Length;i++) {
Console.WriteLine(fileNames[i]);
}
ff.download("Readme.zip",true);
ff.close();
}catch(Exception e) {
Console.WriteLine("Caught Error :"+e.Message);
}
}
}
支援所有的FTP命令、檔案上下傳,
/*
FTPFactory.cs
Better view with tab space=4
use the following line to compile
csc /target:library /out:FTPLib.dll /r:System.DLL FTPFactory.cs
*/
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Net.Sockets;
namespace FtpLib {
public class FTPFactory {
private string remoteHost,remotePath,remoteUser,remotePass,mes;
private int remotePort,bytes;
private Socket clientSocket;
private int retValue;
private Boolean de;
private Boolean logined;
private string reply;
private static int BLOCK_SIZE = 512;
Byte[] buffer = new Byte[BLOCK_SIZE];
Encoding ASCII = Encoding.ASCII;
public FTPFactory() {
remoteHost = "localhost";
remotePath = ".";
remoteUser = "anonymous";
remotePass = "ftpclient@ospreyindia.com";
remotePort = 21;
debug = false;
logined = false;
}
public void setRemoteHost(string remoteHost) {
this.remoteHost = remoteHost;
}
public string getRemoteHost() {
return remoteHost;
}
public void setRemotePort(int remotePort) {
this.remotePort = remotePort;
}
public int getRemotePort() {
return remotePort;
}
public void setRemotePath(string remotePath) {
this.remotePath = remotePath;
}
public string getRemotePath() {
return remotePath;
}
public void setRemoteUser(string remoteUser) {
this.remoteUser = remoteUser;
}
public void setRemotePass(string remotePass) {
this.remotePass = remotePass;
}
public string[] getFileList(string mask) {
if(!logined) {
login();
}
Socket cSocket = createDataSocket();
sendCommand("NLST " + mask);
if(!(retValue == 150 || retValue == 125)) {
throw new IOException(reply.Substring(4));
}
mes = "";
while(true) {
int bytes = cSocket.Receive(buffer, buffer.Length, 0);
mes += ASCII.GetString(buffer, 0, bytes);
if(bytes < buffer.Length) {
break;
}
}
char[] seperator = {'n'};
string[] mess = mes.Split(seperator);
cSocket.Close();
readReply();
if(retValue != 226) {
throw new IOException(reply.Substring(4));
}
return mess;
}
public long getFileSize(string fileName) {
if(!logined) {
login();
}
sendCommand("SIZE " + fileName);
long size=0;
if(retValue == 213) {
size = reply.Substring(4).ToInt64();
}else {
throw new IOException(reply.Substring(4));
}
return size;
}
public void login() {
clientSocket = new Socket(Addresamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
IPEndPoint ep = new IPEndPoint(.Resolve(remoteHost), remotePort);
int i = clientSocket.Connect(ep);
if( i != 0 ) {
throw new IOException("Couldn't connect to remote server");
}
readReply();
if(retValue != 220) {
close();
throw new IOException(reply.Substring(4));
}
if(debug)
Console.WriteLine("USER "+remoteUser);
sendCommand("USER "+remoteUser);
if( !(retValue == 331 || retValue == 230) ) {
cleanup();
throw new IOException(reply.Substring(4));
}
if( retValue != 230 ) {
if(debug)
Console.WriteLine("PASS xxx");
sendCommand("PASS "+remotePass);
if( !(retValue == 230 || retValue == 202) ) {
cleanup();
throw new IOException(reply.Substring(4));
}
}
logined = true;
Console.WriteLine("Connected to "+remoteHost);
chdir(remotePath);
}
public void setBinaryMode(Boolean mode) {
if(mode) {
sendCommand("TYPE I");
}else {
sendCommand("TYPE A");
}
if (retValue != 200) {
throw new IOException(reply.Substring(4));
}
}
public void (string fileName) {
download(fileName,false);
}
public void download(string fileName,Boolean resume) {
if(!logined) {
login();
}
setBinaryMode(true);
long totalSize=0;
try{
totalSize = getFileSize(fileName);
}catch(Exception) {
throw new Exception("File Not Found "+fileName);
}
Console.WriteLine("Downloading file "+fileName+" from "+remoteHost + "/"+remotePath);
if(!File.FileExists(fileName)) {
Stream st = File.Create(fileName);
st.Close();
}
FileStream output = new FileStream(fileName,FileMode.Open);
Socket cSocket = createDataSocket();
long offset = 0;
if(resume) {
offset = output.Length;
if(offset > 0 ) {
sendCommand("REST "+offset);
if(retValue != 350) {
//throw new IOException(reply.Substring(4));
//Server may not support resuming.
offset = 0;
}
}
if(offset > 0) {
if(debug) {
Console.WriteLine("seeking to " + offset);
}
long npos = output.Seek(offset,SeekOrigin.Begin);
Console.WriteLine("new pos="+npos);
}
}
sendCommand("RETR " + fileName);
if(!(retValue == 150 || retValue == 125)) {
throw new IOException(reply.Substring(4));
}
float iCnt = 0;
float per = 0, oldPer = 1;
while(true) {
bytes = cSocket.Receive(buffer, buffer.Length, 0);
output.Write(buffer,0,bytes);
// Showing the progress. 1..50
iCnt += bytes;
per = (int) ( (iCnt / totalSize) * 100 );
if( per != oldPer && per % 2 == 0 ) {
Console.Write(".");
oldPer = per;
}
if(bytes < buffer.Length) {
break;
}
}
output.Close();
cSocket.Close();
Console.WriteLine("");
readReply();
if( !(retValue == 226 || retValue == 250) ) {
throw new IOException(reply.Substring(4));
}
}
public void (string fileName) {
upload(fileName,false);
}
public void upload(string fileName,Boolean resume) {
if(!logined) {
login();
}
Socket cSocket = createDataSocket();
long offset=0;
if(resume) {
try {
setBinaryMode(true);
offset = getFileSize(fileName);
}catch(Exception) {
offset = 0;
}
}
if(offset > 0 ) {
sendCommand("REST " + offset);
if(retValue != 350) {
//throw new IOException(reply.Substring(4));
//Remote server may not support resuming.
offset = 0;
}
}
sendCommand("STOR "+fileName);
if( !(retValue == 125 || retValue == 150) ) {
throw new IOException(reply.Substring(4));
}
// open input stream to read file
FileStream input = new FileStream(fileName,FileMode.Open);
if(offset != 0){
if(debug) {
Console.WriteLine("seeking to " + offset);
}
input.Seek(offset,SeekOrigin.Begin);
}
//for progress bar
long totalSize = input.Length - offset;
float iCnt = 0;
int per = 0, oldPer = 1;
Console.WriteLine("Uploading file "+fileName+" to "+remotePath);
while ((bytes = input.Read(buffer,0,buffer.Length)) > 0) {
cSocket.Send(buffer, bytes, 0);
// Showing the progress. 1..50
iCnt += bytes;
per = (int) ( (iCnt / totalSize) * 100 );
if( per != oldPer && per % 2 == 0 ) {
Console.Write(".");
oldPer = per;
}
}
input.Close();
Console.WriteLine("");
cSocket.Close();
readReply();
if( !(retValue == 226 || retValue == 250) ) {
throw new IOException(reply.Substring(4));
}
}
public void deleteRemoteFile(string fileName) {
if(!logined) {
login();
}
sendCommand("DELE "+fileName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void renameRemoteFile(string oldFileName,string newFileName) {
if(!logined) {
login();
}
sendCommand("RNFR "+oldFileName);
if(retValue != 350) {
throw new IOException(reply.Substring(4));
}
// known problem
// rnto will not take care of existing file.
// i.e. It will overwrite if newFileName exist
sendCommand("RNTO "+newFileName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void mkdir(string dirName) {
if(!logined) {
login();
}
sendCommand("MKD "+dirName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void rmdir(string dirName) {
if(!logined) {
login();
}
sendCommand("RMD "+dirName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
}
public void chdir(string dirName) {
if(dirName.Equals(".")) {
return;
}
if(!logined) {
login();
}
sendCommand("CWD "+dirName);
if(retValue != 250) {
throw new IOException(reply.Substring(4));
}
this.remotePath = dirName;
Console.WriteLine("Current directory is "+remotePath);
}
public void close() {
if( clientSocket != null ) {
sendCommand("QUIT");
}
cleanup();
Console.WriteLine("Closing...");
}
public void setDebug(Boolean debug) {
this.debug = debug;
}
private void readReply() {
mes = "";
reply = readLine();
retValue = reply.Substring(0,3).ToInt32();
}
private void cleanup() {
if(clientSocket!=null) {
clientSocket.Close();
clientSocket = null;
}
logined = false;
}
private string readLine() {
while(true) {
bytes = clientSocket.Receive(buffer, buffer.Length, 0);
mes += ASCII.GetString(buffer, 0, bytes);
if(bytes < buffer.Length) {
break;
}
}
char[] seperator = {'n'};
string[] mess = mes.Split(seperator);
if(mes.Length > 2) {
mes = mess[mess.Length-2];
}else {
mes = mess[0];
}
if(!mes.Substring(3,1).Equals(" ")) {
return readLine();
}
if(debug) {
for(int k=0;k < mess.Length-1;k++) {
Console.WriteLine(mess[k]);
}
}
return mes;
}
private void sendCommand(String command) {
Byte[] cmytes = Encoding.ASCII.GetBytes((command+"rn").ToCharArray());
clientSocket.Send(cmdBytes, cmdBytes.Length, 0);
readReply();
}
private Socket createDataSocket() {
sendCommand("PASV");
if(retValue != 227) {
throw new IOException(reply.Substring(4));
}
int index1 = reply.IndexOf('(');
int index2 = reply.IndexOf(')');
string ipData = reply.Substring(index1+1,index2-index1-1);
int[] parts = new int[6];
int len = ipData.Length;
int partCount = 0;
string buf="";
for (int i = 0; i < len && partCount <= 6; i++) {
char ch = ipData.Substring(i,1).ToChar();
if (Char.IsDigit(ch))
buf+=ch;
else if (ch != ',') {
throw new IOException("Malformed PASV reply: " + reply);
}
if (ch == ',' || i+1 == len) {
try {
parts[partCount++] = buf.ToInt32();
buf="";
}
catch (Exception) {
throw new IOException("Malformed PASV reply: " + reply);
}
}
}
string ipAddress = parts[0] + "."+ parts[1]+ "." +
parts[2] + "." + parts[3];
int port = (parts[4] << 8) + parts[5];
Socket s = new Socket(AddressFamily.AfINet,SocketType.SockStream,ProtocolType.ProtTCP);
IPEndPoint ep = new IPEndPoint(DNS.Resolve(ipAddress), port);
int sucess = s.Connect(ep);
if( sucess != 0 ) {
throw new IOException("Can't connect to remote server");
}
return s;
}
}
}
Following is the listing of a test program which uses this library
/*
File : Test.cs
Better view with tab space=4
use the following line to compile
csc.exe /t:exe /r:System.DLL /r:System.Net.DLL /r:FTPLib.dll /out:"Test.exe" "Test.cs"
*/
using System;
using FtpLib;
public class Test {
public static void Main() {
try {
Console.WriteLine("Starting...");
FTPFactory ff = new FTPFactory();
ff.setDebug(true);
ff.setRemoteHost("192.168.10.19");
ff.setRemoteUser("jaimon");
ff.setRemotePass("mathew");
ff.login();
string[] fileNames = ff.getFileList("*.*");
for(int i=0;i < fileNames.Length;i++) {
Console.WriteLine(fileNames[i]);
}
ff.download("Readme.zip",true);
ff.close();
}catch(Exception e) {
Console.WriteLine("Caught Error :"+e.Message);
}
}
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989336/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- C# mail pop3 clientC#AIclient
- c# 上傳FTP檔案C#FTP
- c#版 mqtt 3.1.1 client 實現C#MQQTclient
- FTP工作原理(轉)FTP
- C# FTP 上傳 下載(彙總)C#FTP
- 摘錄_c# ftp操作程式碼集C#FTP
- FTP命令詳解(轉)FTP
- FTP命令詳解 (轉)FTP
- Error: DPI-1047: Cannot locate a 64-bit Oracle Client library: "問題ErrorOracleclient
- ftp錯誤命令速查(轉)FTP
- 用perl作的ftp(轉)FTP
- FTP的完整類<1><轉>FTP
- FTP的完整類<2><轉>FTP
- FTP的完整類<3><轉>FTP
- Linux下架設FTP(轉)LinuxFTP
- ftp使用簡介(linux)(轉)FTPLinux
- Library cache lock/pin詳解(轉)
- C# FTP上傳下載(支援斷點續傳)C#FTP斷點
- C# 上傳下載ftp(支援斷點續傳)C#FTP斷點
- Navicat for Oracle Instant client required(轉載)OracleclientUI
- C# FTP上傳檔案至伺服器程式碼C#FTP伺服器
- [轉]多CLIENT的SCC4設定client
- MYSQL(解決方法):Client does not support authentication(轉)MySqlclient
- 深入Scripting Runtime Library 之一 (轉)
- C++ Standard Library擴充建議... (轉)C++
- [轉載] RPATH/LD_LIBRARY_PATH/RUNPATH
- 用FTP自動傳送檔案(轉)FTP
- 新手FTP問題,等待高手指導!!!(轉)FTP
- 一個自動ftp的指令碼(轉)FTP指令碼
- aix下新增ftp使用者(轉載)AIFTP
- Beginner with C# (轉)C#
- WHAT IS C# (轉)C#
- 北大FTP,除了北大FTP其他好用的FTP軟體FTP
- FTP非互動方式檔案傳輸(轉)FTP
- 實現FTP多執行緒下載 (轉)FTP執行緒
- 一個完整的ftp遠端批次shell(轉)FTP
- 以Solaris架設FTP虛擬系統(轉)FTP
- Linux下啟動ftp及xdm配置(轉)LinuxFTP