LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C# FTP上传(支持断点续传)

admin
2024年1月12日 17:7 本文热度 537

当前博文只支持上传功能,已经过测试,可以直接使用,但请注意你的使用场景,本人FTP服务端使用 FileZilla Server。

 

日志记录请看君修改成自己的。初始时修改自己的文件目录。本文上传文件采用队列形式。废话就不多说了,直接上代码。

1.  public class LoadFileEventArgs : CancelEventArgs

2.      {

3.          /// <summary>Ftp文件</summary>

4.          public String Src { get; set; }

5.   

6.          /// <summary>Ftp文件目录</summary>

7.          public String SrcDir { get; set; }

8.   

9.          /// <summary>源文件大小</summary>

10.                public Int64 SrcSize { get; set; }

11.         

12.                /// <summary>目标文件</summary>

13.                public String Des { get; set; }

14.         

15.                /// <summary>目标文件大小</summary>

16.                public Int64 DesSize { get; set; }

17.         

18.                /// <summary>断点续传</summary>

19.                public bool FileAppend { get; set; }

20.         

21.                /// <summary>该文件需要压缩</summary>

22.                //public Boolean NeedZipFile { get; set; }

23.         

24.                /// <summary>该文件太大需要分段压缩</summary>

25.                //public Boolean NeedSubZipFile { get; set; }

26.            }

1.  public class FtpHelper

2.      {

3.          public String ftpHostName;

4.          public String ftpUserId;

5.          public String ftpPassword;

6.          public String fileParam;  //  ../Datas/Robot-{参数}/

7.          

8.          private static readonly object sys = new object();

9.          private static FtpHelper instance = null;

10.                private Queue<LoadFileEventArgs> pathQueue = new Queue<LoadFileEventArgs>();

11.         

12.                private String ftpURI {

13.                    get { return String.Format("ftp://{0}", ftpHostName); }

14.                }

15.                private String localDir {

16.                    get { return System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Datas\\"); }

17.                }

18.                private String remoteDir {

19.                    get { return String.Format("Robot-{0}//", fileParam); }

20.                }

21.         

22.                public static FtpHelper Instance

23.                {

24.                    get

25.                    {

26.                        if (instance == null){

27.                            lock (sys){

28.                                if (instance == null)

29.                                    instance = new FtpHelper();

30.                            }

31.                        }

32.         

33.                        return instance;

34.                    }

35.                }

36.                private delegate bool AsyncDelegate(LoadFileEventArgs arg);

37.                private event EventHandler<LoadFileEventArgs> onUploadFileEvent;

38.                private event EventHandler<LoadFileEventArgs> onUploadFileFinishedEvent;

39.                public event EventHandler onMonitorUploadEvent;

40.                private bool IsWorking = false;//上传工作是否在进行;

41.                private FtpWebResponse webresp = null;

42.         

43.         

44.                private FtpHelper() {

45.                    onUploadFileEvent += FtpHelper_onUploadFileEvent;

46.                    onUploadFileFinishedEvent += FtpHelper_onUploadFileFinishedEvent;

47.                    onMonitorUploadEvent += FtpHelper_onMonitorUploadEvent;

48.                    this.onMonitorUploadEvent?.Invoke(null, null); //测试时注释

49.                }

50.         

51.                /// <summary>

52.                /// 测试接口,正式发布时将要注释

53.                /// </summary>

54.                public void FuncInit() {

55.                    

56.                    //UploadDirectory();

57.                }

58.         

59.                /// <summary>

60.                /// 上传目录下文件

61.                /// </summary>

62.                private void UploadDirectory() {

63.                    if (!System.IO.Directory.Exists(localDir)) return;

64.                    String[] fileArray;

65.                    String[] pathArray = System.IO.Directory.GetDirectories(localDir);

66.                    String strDir = String.Empty;

67.                    foreach (String str in pathArray) {

68.                        fileArray = System.IO.Directory.GetFiles(str);

69.                        foreach (String temp in fileArray) {

70.                            InsertQueue(temp, str);

71.                        }

72.                    }

73.         

74.                    //准备上传文件

75.                    PerUpload();

76.                    

77.                }

78.         

79.                /// <summary>

80.                /// 插入队列

81.                /// </summary>

82.                /// <param name="filePath"></param>

83.                /// <param name="dirPath"></param>

84.                void InsertQueue(String filePath, String dirPath = "") {

85.                    if (!System.IO.File.Exists(filePath)) return;

86.                    if (String.IsNullOrEmpty(dirPath)){

87.                        String[] pathArray = System.IO.Directory.GetDirectories(localDir);

88.                        foreach (String str in pathArray){

89.                            if (filePath.Contains(str)){

90.                                dirPath = str;

91.                                break;

92.                            }

93.                        }

94.                    }

95.         

96.                    System.IO.FileInfo fi = new System.IO.FileInfo(filePath);

97.                    String strDir = String.Format("{0}{1}//{2}//{3}//{4}", remoteDir, dirPath.Split('\\').Last(), fi.CreationTime.Date.Year, fi.CreationTime.Date.Month, fi.CreationTime.Date.Day);

98.                    this.pathQueue.Enqueue(new LoadFileEventArgs{

99.                        Des = filePath,

100.                      SrcDir = String.Format("ftp://{0}/{1}", ftpHostName, strDir),

101.                      Src = String.Format("ftp://{0}//{1}/{2}", ftpHostName, strDir, fi.Name),

102.                      DesSize = fi.Length,

103.                      SrcSize = 0,

104.                      FileAppend = false

105.                  });

106.              }

107.       

108.              private void PerUpload() {

109.                  Task.Factory.StartNew(() => {

110.                      if (FTPConnonect()){

111.                          try

112.                          {

113.                              IsWorking = true;

114.                              AsyncDelegate uploadDelegate;

115.                              while (this.pathQueue != null && this.pathQueue.Count > 0){

116.                                  if (!FTPConnonect())

117.                                      break;

118.       

119.                                  System.Threading.Thread.Sleep(100);

120.                                  LoadFileEventArgs args = this.pathQueue.Peek();

121.                                  //检查上传文件所在的目录是否存在,不存在则创建所在的目录。

122.                                  MakeDir(args.SrcDir);

123.                                  //检查文件是否已存在并判断文件大小

124.                                  Boolean res = HandelMatchFile(args);

125.                                  if (!res){

126.                                      //FTP服务器上文件已存在,删除准备出栈的队列。

127.                                      this.pathQueue.Dequeue();

128.                                      continue;

129.                                  }

130.       

131.                                  uploadDelegate = new AsyncDelegate(instance.Upload);

132.                                  IAsyncResult iasync = uploadDelegate.BeginInvoke(args, new AsyncCallback(FuncCallBack), null);

133.                                  bool result = uploadDelegate.EndInvoke(iasync);

134.                                  if (result){

135.                                      this.onUploadFileFinishedEvent?.Invoke(null, args);

136.                                  }

137.                                  else

138.                                      this.pathQueue.Dequeue();

139.                              }

140.                          }

141.                          catch (System.Exception ex){

142.                              SaveLog.WriteLog(new LogObj() { MessageText = String.Format("文件上传FTP服务器端异常:{0}", ex.ToString()), MessageType = LogType.Info });

143.                          }

144.                          finally {

145.                              IsWorking = false;

146.                          }

147.                      }

148.                  });

149.              }

150.       

151.              private bool FTPConnonect(){

152.                  DateTime currTime = DateTime.Now;

153.                  int timed = 300; //约定定时时长300s=5分钟。

154.       

155.                  while (true){

156.                      try

157.                      {

158.                          //超过约定时长,退出循环

159.                          if (DateTime.Now.Subtract(currTime).Seconds > timed)

160.                              return false;

161.       

162.                          using (webresp = (FtpWebResponse)SetFtpWebRequest(ftpURI, WebRequestMethods.Ftp.ListDirectory).GetResponse()){

163.                              webresp.Dispose();

164.                              webresp.Close();

165.       

166.                              return true;

167.                          }

168.                      }

169.                      catch (Exception ex){

170.                          SaveLog.WriteLog(new LogObj() { MessageText = String.Format("FTP服务器端连接失败,异常:{0}", ex.ToString()), MessageType = LogType.Info });

171.                          if (webresp != null){

172.                              webresp.Dispose();

173.                              webresp.Close();

174.                          }

175.       

176.                          System.Threading.Thread.Sleep(10000);

177.                      }

178.                  }

179.              }

180.       

181.              /// <summary>

182.              /// 文件上传

183.              /// </summary>

184.              /// <param name="arg"></param>

185.              /// <returns></returns>

186.              private bool Upload(LoadFileEventArgs arg) {

187.                  Stream reqStream = null;

188.                  FileStream fs = null;

189.                  FtpWebResponse uploadResponse = null;

190.       

191.                  Uri uri = new Uri(arg.Src);

192.                  FtpWebRequest reqFtp = (FtpWebRequest)WebRequest.Create(uri);

193.                  reqFtp.Method = WebRequestMethods.Ftp.UploadFile;

194.                  reqFtp.KeepAlive = false;

195.                  reqFtp.Credentials = new NetworkCredential(ftpUserId, ftpPassword);

196.                  reqFtp.UsePassive = false;

197.                  reqFtp.UseBinary = true;

198.                  reqFtp.ContentLength = arg.DesSize;

199.                  reqFtp.Timeout = 10000;

200.                  fs = System.IO.File.Open(arg.Des, FileMode.Open);

201.                  byte[] buffer = new byte[2024];

202.                  int bytesRead;

203.       

204.                  try

205.                  {

206.                      if (arg.FileAppend){

207.                          //断点续传

208.                          reqFtp.Method = WebRequestMethods.Ftp.AppendFile;

209.                          reqFtp.ContentOffset = arg.SrcSize;

210.                          //fs.Position = arg.SrcSize;

211.                          fs.Seek(arg.SrcSize, 0);

212.                      }

213.       

214.                      using (reqStream = reqFtp.GetRequestStream()){

215.                          while (true){

216.                              bytesRead = fs.Read(buffer, 0, buffer.Length);

217.                              if (bytesRead == 0)

218.                                  break;

219.       

220.                              reqStream.Write(buffer, 0, bytesRead);

221.                          }

222.       

223.                          reqStream.Dispose();

224.                          reqStream.Close();

225.                      }

226.       

227.                      uploadResponse = reqFtp.GetResponse() as FtpWebResponse;

228.                      return true;

229.                  }

230.                  catch (Exception ex){

231.                      SaveLog.WriteLog(new LogObj() { MessageText = String.Format("上传文件到ftp服务器出错:{0}", ex.ToString()), MessageType = LogType.Info });

232.                      return false;

233.                  }

234.                  finally{

235.                      if (reqStream != null){

236.                          reqStream.Dispose();

237.                          reqStream.Close();

238.                      }

239.       

240.                      if (fs != null){

241.                          fs.Dispose();

242.                          fs.Close();

243.                      }

244.       

245.                      if (uploadResponse != null){

246.                          uploadResponse.Dispose();

247.                          uploadResponse.Close();

248.                      }

249.                  }

250.              }

251.       

252.              /// <summary>

253.              /// 回调函数,暂时保留

254.              /// </summary>

255.              /// <param name="res"></param>

256.              void FuncCallBack(IAsyncResult res) {

257.                  if (res.IsCompleted)

258.                  {

259.                      //暂时保留

260.                  }

261.              }

262.       

263.              /// <summary>

264.              /// FTP服务器端创建文件夹。

265.              /// </summary>

266.              /// <param name="strPath"></param>

267.              private void MakeDir(String strPath) {

268.                  try{

269.                      if (RemoteDirExist(strPath)) return;

270.                      using (webresp = (FtpWebResponse)SetFtpWebRequest(strPath, WebRequestMethods.Ftp.MakeDirectory).GetResponse()){

271.                          using (Stream ftpStream = webresp.GetResponseStream()){

272.                              ftpStream.Dispose();

273.                              ftpStream.Close();

274.                              webresp.Dispose();

275.                              webresp.Close();

276.                          }

277.                      }

278.                  }

279.                  catch (Exception ex){

280.                      SaveLog.WriteLog(new LogObj() { MessageText = String.Format("FTP服务器端创建文件夹异常:{0}", ex.ToString()), MessageType = LogType.Info });

281.                  }

282.              }

283.       

284.              /// <summary>

285.              /// 检查FTP服务端所匹配的文件(服务器断网、客户端断网等多种因素造成)

286.              /// </summary>

287.              private Boolean HandelMatchFile(LoadFileEventArgs args) {

288.                  Boolean res = true;

289.                  Tuple<int, int> tuple = CompareFileSize(args);

290.                  switch (tuple.Item1) {

291.                      case 1:

292.                          break;

293.                      case 2:

294.                          //尝试断点续传服务端文件

295.                          args.FileAppend = true;

296.                          args.SrcSize = tuple.Item2;

297.                          res = true;

298.                          break;

299.                      case 3:

300.                          try

301.                          {

302.                              //删除本地文件

303.                              System.IO.File.Delete(args.Des);

304.                          }

305.                          catch (System.Exception ex){

306.                              SaveLog.WriteLog(new LogObj() { MessageText = String.Format("###删除本地文件失败,异常原因:{0}", ex.Message), MessageType = LogType.Error });

307.                          }

308.                          res = false;

309.                          break;

310.                      default:

311.                          res = false;

312.                          break;

313.                  }

314.       

315.                  return res;

316.              }

317.       

318.              /// <summary>

319.              /// 检查FTP服务端是否存在当前目录

320.              /// </summary>

321.              /// <param name="remoteDirName"></param>

322.              /// <returns></returns>

323.              private bool RemoteDirExist(String remoteDirName) {

324.                  try{

325.                      using (webresp = (FtpWebResponse)SetFtpWebRequest(remoteDirName, WebRequestMethods.Ftp.ListDirectoryDetails).GetResponse()) {

326.                          webresp.Dispose();

327.                          webresp.Close();

328.                          return true;

329.                      }

330.                  }

331.                  catch (System.Exception ex){

332.                      if (webresp != null){

333.                          webresp.Dispose();

334.                          webresp.Close();

335.                      }

336.       

337.                      SaveLog.WriteLog(new LogObj() { MessageText = String.Format("检查FTP服务器端目录文件造成异常:{0}", ex.ToString()), MessageType = LogType.Info });

338.                      return false;

339.                  }

340.              }

341.       

342.              /// <summary>

343.              /// 获取FTP服务端文件基本信息(文件名、大小),文件不存在返回空

344.              /// </summary>

345.              /// <param name="arg"></param>

346.              /// <returns></returns>

347.              private String GetRemoteFileDetails(String uri) {

348.                  StreamReader sr = null;

349.                  String content = String.Empty;

350.                  try

351.                  {

352.                      using (webresp = (FtpWebResponse)SetFtpWebRequest(uri, WebRequestMethods.Ftp.ListDirectoryDetails).GetResponse()){

353.                          using (sr = new StreamReader(webresp.GetResponseStream(), Encoding.Default)){

354.                              content = sr.ReadLine();

355.       

356.                              sr.Dispose();

357.                              sr.Close();

358.                              webresp.Dispose();

359.                              webresp.Close();

360.       

361.                              return content;

362.                          }

363.                      }

364.                  }

365.                  catch(System.Exception ex){

366.                      if (sr != null){

367.                          sr.Dispose();

368.                          sr.Close();

369.                      }

370.       

371.                      if (webresp != null){

372.                          webresp.Dispose();

373.                          webresp.Close();

374.                      }

375.       

376.                      //SaveLog.WriteLog(new LogObj() { MessageText = String.Format("获取FTP服务器端文件信息时产生异常:{0}", ex.ToString()), MessageType = LogType.Info });

377.                      return content;

378.                  }

379.              }

380.       

381.              /// <summary>

382.              /// 删除FTP服务端文件

383.              /// </summary>

384.              /// <param name="uri"></param>

385.              private void DelRemoteFile(String uri)

386.              {

387.                  StreamReader sr = null;

388.                  String content = String.Empty;

389.                  try

390.                  {

391.                      using (webresp = (FtpWebResponse)SetFtpWebRequest(uri, WebRequestMethods.Ftp.DeleteFile).GetResponse()){

392.                          using (sr = new StreamReader(webresp.GetResponseStream(), Encoding.Default)){

393.                              content = sr.ReadToEnd();

394.       

395.                              sr.Dispose();

396.                              sr.Close();

397.                              webresp.Dispose();

398.                              webresp.Close();

399.                          }

400.                      }

401.                  }

402.                  catch

403.                  {

404.                      if (sr != null){

405.                          sr.Dispose();

406.                          sr.Close();

407.                      }

408.       

409.                      if (webresp != null){

410.                          webresp.Dispose();

411.                          webresp.Close();

412.                      }

413.                  }

414.              }

415.       

416.              /// <summary>

417.              /// 设置FTP WebRequest参数

418.              /// </summary>

419.              /// <param name="uri"></param>

420.              /// <param name="webRequestMethods"></param>

421.              /// <param name="timeOut"></param>

422.              /// <returns></returns>

423.              FtpWebRequest SetFtpWebRequest(String uri, String webRequestMethods, int timeOut=3000) {

424.                  FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(new Uri(uri));

425.                  ftpRequest.Method = webRequestMethods;

426.                  ftpRequest.UsePassive = false;

427.                  ftpRequest.UseBinary = true;

428.                  ftpRequest.KeepAlive = false;

429.                  ftpRequest.Timeout = timeOut;

430.                  ftpRequest.Credentials = new NetworkCredential(ftpUserId, ftpPassword);

431.                  return ftpRequest;

432.              }

433.       

434.              /// <summary>

435.              /// 对比远程文件大小

436.              /// 1. 远程无此文件返回 --- 1

437.              /// 2. 远程文件比本地小 --- 2

438.              /// 3. 远程文件与本地大小一致 --- 3

439.              /// </summary>

440.              /// <param name="args"></param>

441.              /// <returns></returns>

442.              private Tuple<int, int> CompareFileSize(LoadFileEventArgs args) {

443.                  String content = GetRemoteFileDetails(args.Src);

444.                  if (String.IsNullOrEmpty(content))

445.                      return new Tuple<int, int>(1, 0);

446.       

447.                  //匹配已上传文件的大小

448.                  Regex regex = new Regex(@"^-.+?\sftp.+?\s+(?<size>\d+)", RegexOptions.IgnoreCase);

449.                  Match match = regex.Match(content);

450.                  if (match.Success) {

451.                      int fileSize = Convert.ToInt32(match.Groups["size"].Value);

452.                      if (fileSize < args.DesSize)

453.                          return new Tuple<int, int>(2, fileSize);

454.       

455.                      return new Tuple<int, int>(3, fileSize);

456.                  }

457.       

458.                  return new Tuple<int, int>(2, 0);

459.              }

460.       

461.              /// <summary>

462.              /// 获取FTP服务器端文件大小

463.              /// </summary>

464.              /// <param name="src"></param>

465.              /// <returns></returns>

466.              long GetRemoteFileSize(String src) {

467.                  long size;

468.                  try

469.                  {

470.                      using (webresp = (FtpWebResponse)SetFtpWebRequest(src, WebRequestMethods.Ftp.GetFileSize).GetResponse()) {

471.                          size = webresp.ContentLength;

472.                          webresp.Dispose();

473.                          webresp.Close();

474.                          return size;

475.                      }

476.                  }

477.                  catch (System.Exception ex) {

478.                      if (webresp != null) {

479.                          webresp.Dispose();

480.                          webresp.Close();

481.                      }

482.       

483.                      SaveLog.WriteLog(new LogObj() { MessageText = String.Format("获取FTP服务器端文件大小时产生异常:{0}", ex.ToString()), MessageType = LogType.Info });

484.                      return 0;

485.                  }

486.              }

487.       

488.              /// <summary>

489.              /// 单个文件上传完毕,触发此事件

490.              /// </summary>

491.              /// <param name="sender"></param>

492.              /// <param name="e"></param>

493.              private void FtpHelper_onUploadFileFinishedEvent(object sender, LoadFileEventArgs e){

494.                  //String content = GetRemoteFileDetails(e.Src);

495.                  long size = GetRemoteFileSize(e.Src);

496.                  if (size == 0) {

497.                      SaveLog.WriteLog(new LogObj() { MessageText = String.Format("###当前上传的文件可能出现异常或者远程无法连接上,文件源路径:{0}; 上传服务器路径:{1}", e.Des, e.Src), MessageType = LogType.Error });

498.                  }

499.                  else

500.                  {

501.                      if (size == e.DesSize){

502.                          SaveLog.WriteLog(new LogObj() { MessageText = String.Format("###文件上传成功文件大小为{0}, 服务器路径:{1}", e.DesSize, e.Src), MessageType = LogType.Error });

503.                          this.pathQueue.Dequeue();//删除准备出栈的队列

504.       

505.                          try

506.                          {

507.                              //删除本地文件

508.                              System.IO.File.Delete(e.Des);

509.                          }

510.                          catch (System.Exception ex)

511.                          {

512.                              SaveLog.WriteLog(new LogObj() { MessageText = String.Format("###删除本地文件失败,异常原因:{0}", ex.Message), MessageType = LogType.Error });

513.                          }

514.                      }

515.                      else {

516.                          SaveLog.WriteLog(new LogObj() { MessageText = "###文件上传完毕,但本地与远程文件大小不一致,将删除远程文件再重新上传。", MessageType = LogType.Error });

517.                          DelRemoteFile(e.Src);

518.                      }

519.                  }

520.              }

521.       

522.              private void FtpHelper_onUploadFileEvent(object sender, LoadFileEventArgs e){

523.       

524.              }

525.       

526.              private void FtpHelper_onMonitorUploadEvent(object sender, EventArgs e){

527.                  Task.Factory.StartNew(() => {

528.                      while (true) {

529.                          if (FTPConnonect()){

530.                              if (!IsWorking && this.pathQueue != null && this.pathQueue.Count > 0){

531.                                  PerUpload();

532.                                  System.Threading.Thread.Sleep(5000);

533.                              }

534.                              else if (!IsWorking && (this.pathQueue == null || this.pathQueue.Count == 0)){

535.                                  UploadDirectory();

536.                                  System.Threading.Thread.Sleep(5000);

537.                              }

538.                              else if (IsWorking){

539.                                  System.Threading.Thread.Sleep(5000);

540.                              }

541.                          }

542.                          else

543.                              System.Threading.Thread.Sleep(10000);

544.                      }

545.                  });

546.              }

547.       

548.              /// <summary>

549.              /// 上传文件到FTP服务端

550.              /// </summary>

551.              /// <param name="src">本地文件路径</param>

552.              public void Put(String src) {

553.                  String path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, src);

554.                  InsertQueue(path, String.Empty);

555.              }

556.          }


该文章在 2024/1/12 17:07:11 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved