这个perl文件将执行的任务是, 按照指定的文件夹目录,自动将该文件夹下的所有文件上传到指定ftp站点的指定目录下

本应用程序设计的几个基本理念是:
工具箱再利用:尽可能利用已有的工具;
简化运行步骤;不引入过多的业务逻辑,满足的需求越简单越好。

所以,我们定义了本应用程序依赖于以下几个工具的运行:
ActivePerl-5.8.4.810-MSWin32-x86
Upload.pl
Upload.config

我们将主要的执行逻辑都放在Perl源文件Upload.pl中了,配置文件为Upload.config。

这个perl文件将执行的任务是, 按照指定的文件夹目录,自动将该文件夹下的所有文件上传到指定ftp站点的指定目录下。

这个Perl脚本实际是从Uwe Keim 的《Perl Script for uploading modified files to a FTP-Server》继承下来的,
只不过增加了容错反应和读取外部配置文件的部分,刨掉了与一般业务逻辑无关的读写access文件的部分。

程序大致的流程:
第一步,尝试登陆ftp站点;
第二步,在指定文件夹A类下寻找符合条件的文件,并将A类文件上传到FTP站点指定目录下;
第三步,如果A类文件们全部上传成功,那么在指定文件夹B类下寻找指定文件, 并且上传到FTP指定目录下
第四步,写成功/失败日志。

最后,要写的成功/失败日志的格式如下: 
成功: 生成一个名为“Upload_Succ_2005_01_04_17_23.log”的日志文件
文件格式:输出上传时间,以及所有上传文件名及其大小和耗费的时间。
失败: 生成一个名为“Upload_Fail_2005_01_04_17_23.log”的日志文件
文件格式:输出上传时间,以及已经上传的文件名及其大小和耗费的时间,和失败的文件名及原因。

配置perl脚本运行有两个办法:
您可以在Windows计划任务中配置运行“Perl Upload.pl”的时间,这需要在Windows环境中配置ActivePerl 5.8.4.810;
您也可以利用Perl2Exe(p2x-8.40-Win32)来将perl脚本编译为一个exe可执行程序,在计划任务中运行这个exe(这需要PerlCRT.dll在系统路径下)。

[注意!]在运行之前,您必须修改“Upload.config”文件以配置所需的重要参数。
外部配置参数

在和perl脚本同一目录下的“Upload.config”配置文件中,是事先配置的六个外部参数: 
参数1: ftp_server:
FTP服务器的IP地址。

参数2: ftp_dir:
指定的FTP上传目录路径;

参数3: ftp_uid:
FTP的登陆用户名;

参数4: ftp_pw:
FTP的登陆密码;

参数5: src_dir_WAVFiles,这是一个数组:
指定A类文件夹,放置所有要上传的语音文件;
注意:这个目录下的子文件夹也会被上传。

参数6: src_dir_NamesListFile,这是一个数组:
指定B类文件夹,放置B类文件.
注意:这个目录下的子文件夹也会被上传。

附录:
Upoad.pl内容:

复制代码代码如下:
#!/usr/bin/perl -w
##--------------------------------
#
# 工程项目: FTP自动上传两类文件
#
# 模块名称: FTPAutoUpload
#
# 模块任务: 按照指定的文件夹目录,自动将该文件夹下的所有文件上传到指定ftp站点的指定目录下
#
# 程序名称:     Upload.pl
#
##-------------------------------
##---------------------------#
## 引用的库声明 2
#use strict;
use File::Copy;
use File::stat;
use File::Find;
use Net::FTP;
use Date::Pcalc qw(Delta_DHMS);
use Date::Parse;
use Win32::OLE;
use Win32::OLE::Variant;
##---------------------------#
##---------------------------#
## 引用的库声明 1
#- 读取ini配置文件的库
use Config::IniFiles;
my $cfg = Config::IniFiles->new( -file => "Upload.config" );
##---------------------------#
##---------------------------#
## 从配置文件读取外部参数 ##
##
## FTP服务器的IP地址 ##
$ftp_server    = $cfg->val('FTPServer', 'ftp_server') || '';
## 指定的FTP上传目录路径 ##
#! 切记:文件夹最后不要加"/"符号 !#
$ftp_dir    = $cfg->val('FTPServer', 'ftp_dir') || '';
## FTP的登陆用户名 ##
$ftp_uid   = $cfg->val('FTPServer', 'ftp_uid') || '';
## FTP的登陆密码 ##
$ftp_pw     = $cfg->val('FTPServer', 'ftp_pw') || '';
## 指定文件夹“语音文件”,放置所有要上传的语音文件 ##
#! 切记:文件夹最后不要加"\\"符号 !#
@src_dir_WAVFiles = $cfg->val('SrcDirectory', 'src_dir_WAVFiles');
## 指定文件夹“命名对照列表文件TXT”,放置命名对照列表文件 ##
#! 切记:文件夹最后不要加"\\"符号 !#
@src_dir_NamesListFile = $cfg->val('SrcDirectory', 'src_dir_NamesListFile');
## 一个字符串集合,表明哪些类型的文件/文件夹将不被上传到服务器 ##
@wc_exclude   = ("_vti",".mdb","\\bak","\\data","server.inc");
##---------------------------#
##---------------------------#
## 记录全部过程的日志文件准备
$logfilename = 'upload.log';
$log_cnt = 0;
LOG("");
LOG("自动上传FTP文件 Version 0.1");
LOG("");
LOG("用法: Perl Upload.pl");
LOG("");
##---------------------------#
##---------------------------#
##=== 程序执行的第一步:尝试登陆ftp站点 ==========================##
##  $total_files是上传文件的数目
$total_files = 0;
##  $processed_files是已上传文件的数目
$processed_files = 0;
##  $skipped_files是跳过文件的数目
$skipped_files = 0;
##  $start_date计算出当前开始的时间
$start_date = timeString(time);
## $g_nUploadSuccess代表是否已经完全上传,-1为不是,1为是:
my $g_nUploadSuccess = 1;
## $g_nIsAllWAVsFile_UploadSuccess代表是否已经完全将A类文件上传,-1为不是,1为是:
my $g_nIsAllWAVsFile_UploadSuccess = 1;
## $g_strLastError代表上次错误原因:
my $g_strLastError = "";
LOG("正在链接至指定FTP服务器($ftp_server)...");
$ftp = Net::FTP->new($ftp_server);
if($@)
{
 $g_strLastError = "不能连接到FTP服务器,错误原因:".$@;
 LOG("$g_strLastError@\n");
 $g_nUploadSuccess = -1;
}
else
{
 $ftp->login($ftp_uid, $ftp_pw);
 if($@)
 {
  $g_strLastError = "不能登陆FTP服务器,错误原因:".$@;
  LOG("$g_strLastError\n");
  $g_nUploadSuccess = -1;
 }
 else
 {
  $ftp->binary;
  LOG("链接FTP服务器成功!");
##---------------------------#
##---------------------------#
##=== 程序执行的第二步,将指定A类文件夹下所有A类文件上传到FTP站点指定目录下 ===##
  my %lookup;
  LOG("准备上传“A类文件”目录(@src_dir_WAVFiles)下的所有文件!");
  find(\&processFiles, @src_dir_WAVFiles);
  LOG("目录(@src_dir_WAVFiles)已经处理完毕,结果是:");
##---------------------------#
##=== 程序执行的第三步,将指定B类文件夹下B类文件上传到FTP站点指定目录下 ===##
  if($g_nIsAllWAVsFile_UploadSuccess > 0)
  {
   LOG("+===============================+");
   LOG("准备上传B类目录(@src_dir_NamesListFile)下的所有文件!");
   find(\&processFiles, @src_dir_NamesListFile);
   LOG("目录(@src_dir_NamesListFile)已经处理完毕,结果是:");
   LOG("-===============================-");
  }
  else
  {
   LOG("-===============================-");
   LOG("由于A类文件目录并没有完全上传,所以本B类文件不上传!");
   LOG("-===============================-");
  }
##---------------------------#
##---------------------------#
# 日志文件的最后是一个统计报告
  $span = calcDeltaSeconds($start_date,timeString(time));
  LOG("上传结果:成功。\n花费:$span 秒, 总共处理了 $total_files 个文件, 其中 $processed_files 上传成功, 跳过了 $skipped_files 个文件。");
  $ftp->quit()         or warn "unable to quit: $@\n";
 }
 closeLogfile();
}
##---------------------------#
##---------------------------#
##=== 程序执行的第四步,写成功日志 ===============================##
if($g_nIsAllWAVsFile_UploadSuccess > 0 && $g_nUploadSuccess > 0)
{
 $logfilename = 'Upload_Succ_'.shortTimeString(time).'.log';
 $log_cnt = 0;
 LOG("");
 LOG("FTP自动上传文件 Version 0.1");
 LOG("");
 LOG("上传结果:成功。\n花费:$span 秒, 总共处理了 $total_files 个文件, 其中 $processed_files 上传成功, 跳过了 $skipped_files 个文件。");
 LOG("");
 closeLogfile();
}
##---------------------------#
##---------------------------#
##=== 程序执行的第四步,写失败日志 ===============================##
if($g_nIsAllWAVsFile_UploadSuccess < 0 || $g_nUploadSuccess < 0)
{
 $logfilename = 'Upload_Fail_'.shortTimeString(time).'.log';
 $log_cnt = 0;
 LOG("");
 LOG("FTP自动上传文件 Version 0.1");
 LOG("");
 LOG("上传结果:失败。失败原因:$g_strLastError。\n花费:$span 秒, 总共处理了 $total_files 个文件, 其中 $processed_files 上传成功, 跳过了 $skipped_files 个文件。");
 LOG("");
 closeLogfile();
}
##---------------------------#
## 以下是子函数体的定义
##----------------------------##
##
## 函数名称:processFiles
## 功能:   
##           得到指定文件夹下的所有文件以及子文件夹,然后依次处理它们。
##
## 程序员:  Uwe Keim
##
## 历史记录:
## 编号     日期       作者    备注
## 1        2000       Uwe Keim

##
##----------------------##
sub processFiles
{
 my $srcdir = fsToBs($File::Find::dir);
 my $srcpath = fsToBs($File::Find::name);
 my $base = fsToBs($File::Find::topdir);
 foreach my $exclude (@wc_exclude) {
  if ( index($srcpath, $exclude)>-1 ) {
   $File::Find::prune = 1 if -d $srcpath;
   return;
  }
 }
 # no DIRECT processing of directories.
 if ( -d $srcpath ) {
  return;
 }
 my $dstdir = $srcdir;
 my $dstpath = $srcpath;
 $dstdir =~ s{\Q$base\E}{$ftp_dir}is;
 $dstpath =~ s{\Q$base\E}{$ftp_dir}is;
 $dstdir = bsToFs($dstdir);
 $dstpath = bsToFs($dstpath);
 processFile($srcpath,$dstpath,$dstdir);
}
sub processFile
{
 my ($src,$dst,$dstdir) = @_;
 $total_files++;
 LOG("正在处理文件 $total_files \"$src\"...");
 # --------------------
 # check time.
 my $need_upload = 0;
 # create time.
 my $t1 = $lookup{$src};
 my $t2 = timeString(stat($src)->mtime);
 if ( not defined $t1 ) {
  $lookup{$src} = $t2;
  $need_upload = 1;
 } else {
  my $delta_sec = calcDeltaSeconds($t1,$t2);
  $need_upload = 1 if $delta_sec>5;     # 5 seconds as tolerance.
 }
 # --------------------
 if ( $need_upload>0 ) {
  $processed_files++;
  LOG("正在上传文件:从源 \"$src\" 到目标 \"$dst\"...");
  $ftp->mkdir($dstdir,1);
  $ftp->put($src, $dst) or  $g_nIsAllWAVsFile_UploadSuccess=-1;
  if($g_nIsAllWAVsFile_UploadSuccess < 0)
  {
   LOG("不能上传文件:从源 \"$src\" 到目标 \"$dst\" (dst-dir: \"$dstdir\")。\n");
   if($@)
   {
    LOG("错误原因是:$@\n");
   }
  }
 } else {
  $skipped_files++;
 }
}
sub bsToFs {
 my ($s) = @_;
 $s =~ s/\\/\//gis;
 return $s;
}
sub fsToBs {
 my ($s) = @_;
 $s =~ s/\//\\/gis;
 return $s;
}
sub timeString {
 my ($tm) = @_;
 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($tm);
 return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
}
sub shortTimeString {
 my ($tm) = @_;
 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($tm);
 return sprintf("%04d_%02d_%02d_%02d_%02d", $year+1900, $mon+1, $mday, $hour, $min);
}
# input dates as string "YYYY-MM-DD HH:MM:SS".
# earlier as first parameter, later as second.
sub calcDeltaSeconds {
 my ($t1,$t2) = @_;
 my ($year1,$month1,$day1,$hh1,$mm1,$ss1) = scanDate($t1);
 my ($year2,$month2,$day2,$hh2,$mm2,$ss2) = scanDate($t2);
 my ($days, $hours, $minutes, $seconds) = Delta_DHMS(
  $year1, $month1, $day1, $hh1, $mm1, $ss1,     # earlier.
  $year2, $month2, $day2, $hh2, $mm2, $ss2);    # later.
 return $seconds + $minutes*60 + $hours*60*60 + $days*60*60*24.
}
sub removeFilename {
 my ($s) = @_;
 my $pos = rindex($s,'\\');
 return substr($s, 0, $pos);
}
# format: "2000-09-29 09:09:51".
sub scanDate {
 my ($date) = @_;
 my ($year, $month, $day, $hour, $minute, $seconds);
 $year   = substr($date, 0, 4);
 $month  = substr($date, 5, 2);
 $day   = substr($date, 8, 2);
 $hour   = substr($date, 11, 2);
 $minute  = substr($date, 14, 2);
 $seconds = substr($date, 17, 2);
 return ($year, $month, $day, $hour, $minute, $seconds);
}
sub LOG {
 my ($text) = @_;
 my $time = timeString time;
 # log to stdout.
 print "[$time] $text\n";
 # log to logfile.
 my $LOG_STEP = 10;
 flushLogfile() if ($log_cnt % $LOG_STEP)==0 or $log_cnt==0;
 $log_cnt++;
 print HLOG "[$time] $text\n";
}
sub openLogfile {
 closeLogfile();
 open(HLOG,">>$logfilename") or die("打开日志文件出错:文件名为 $logfilename ;错误原因为: $!"); 
};
sub closeLogfile {
 close HLOG if defined HLOG;
}
sub flushLogfile {
 closeLogfile();
 openLogfile();
}
附录:
Upoad.config内容:
## 配置的外部参数 ##
##
[FTPServer]
#- FTP服务器的IP地址 -#
ftp_server   =
#- 指定的FTP上传目录路径 -#
#! 切记:文件夹最后不要加"/"符号 !#
ftp_dir       =
#- FTP的登陆用户名 -#
ftp_uid    =
#- FTP的登陆密码 -#
ftp_pw    =
## 配置的外部参数 ##
##
[SrcDirectory]
#- 指定文件夹“语音文件”,放置所有要上传的语音文件 -#
#! 切记:文件夹最后不要加"\"符号 !#
src_dir_WAVFiles  =
#- 指定文件夹“命名对照列表文件TXT”,放置命名对照列表文件 -#
#! 切记:文件夹最后不要加"\"符号 !#
src_dir_NamesListFile =

原文链接:http://www.jb51.net/article/4979.htm

【转】FTP自动上传文件的perl脚本以及配置文件的更多相关文章

  1. linux下使用ftp传递文件的shell脚本

    使用ftp传递文件,传递过程中防止对方取文件,后缀名为writing,传完后再改回来. #!/bin/bash dstpath=cnet ftpip="127.0.0.1" log ...

  2. shell 脚本FTP自动上传文件

    下面的脚本 会把本地的文本文件压缩后, 上传到FTP服务器上. 里面有一点小逻辑, 就是上传的文本文件 是 日期时间.txt 形式的, 一天写一个日志文件, 今天的文件不上传, 只上传 老的日志文件. ...

  3. shell脚本实现FTP自动上传文件

    -----多个文件----- #!/bin/bash ftp -n<<! open 172.20.10.242 user logftp logftp binary cd /data/ftp ...

  4. ftp/sftp定时自动上传文件脚本(CentOS)

    1.ftp自动上传文件脚本 #!/bin/bash ftp -n<<! open 192.168.220.129 user ls toor binary hash cd /path/to/ ...

  5. c#.net从ftp下载文件到本地

    c#.net从ftp下载文件到本地      /*首先从配置文件读取ftp的登录信息*/  ;                     ;                     , buffer_c ...

  6. 用DOS批处理实现FTP自动上传、下载、清理文件

    用DOS批处理实现FTP自动上传.下载.清理文件 最近好像特别的忙,好久没来写点东西了,今天写了一个利用批处理程序完成FTP自动上传.下载.清理文件的程序.赶紧 记录下来,以备日后之用.功能介绍:自动 ...

  7. csv,txt,excel文件之间的转换,perl脚本

    最近接触一些需要csv,txt,excel文件之间的转换,根据一些网上搜索加上自己的改动,实现自己想要的结果为主要目的,代码的出处已经找不到了,还请见谅,以下主要是针对csv&excel 和t ...

  8. FTP下载文件失败

    这几天的定时任务下载文件的脚本失败了. 于是手工执行测试,发现报550 Permission denied. Passive mode refused. 意思就是被动模式下,没有权限获取文件. 解决方 ...

  9. crontab不执行perl脚本分析

    在新装的Linux服务器上部署了一个作业监控磁盘空间并提前告警,在shell脚本里面调用了一个perl脚本发送告警邮件.结果出现了一个很奇怪的现象:如果手工执行该脚本/home/oracle/scri ...

随机推荐

  1. iOS之原生地图与高德地图

    原生地图 1.什么是LBS LBS: 基于位置的服务 Location Based Service 实际应用:大众点评,陌陌,微信,美团等需要用到地图或定位的App 2.定位方式 1.GPS定位 2. ...

  2. Linux安装Oracle 11G过程(测试未写完)

    一.简介 Oracle数据库在系统运维中的重要性不言而喻,通过熟悉Oracle的安装来加深对操作系统和数据库知识的了解.Linux安装Oracle前期修改linux内核参数很重要,其实就是linux下 ...

  3. CSS-Sprite-Generator丨CSS雪碧在线生成器

    http://cn.spritegen.website-performance.org/ Css Sprite Tools实现背景图片整合 http://www.onlinedown.net/soft ...

  4. oracle中的sql%rowcount

    sql%rowcount用于记录修改的条数,就如你在sqlplus下执行delete from之后提示已删除xx行一样,这个参数必须要在一个修改语句和commit之间放置,否则你就得不到正确的修改行数 ...

  5. poisspdf(so also poisscdf, poissfit, poissinv, poissrnd, poisstat, pdf.)

    Poisson分布的累积概率值 命令:poisscdf 格式:poisscdf (k, Lambda) Poisson分布 在二项分布中,当n的值很大,p的值很小,而np又较适中时,用Poisson分 ...

  6. 【最短路】ACdream 1198 - Transformers' Mission

    Problem Description A group of transformers whose leader is Optimus Prime(擎天柱) were assigned a missi ...

  7. hishop网站迁移后出现DataProtectionConfigurationProvider错误(转)

    配置错误说明: 在处理向该请求提供服务所需的配置文件时出错.请检查下面的特定错误详细信息并适当地修改配置文件.分析器错误信息: 未能使用提供程序“DataProtectionConfiguration ...

  8. es6模板字符串 问题记录

    自古无图无真相,望各位博主在条件允许的情况下,配张图片吧! 界面是用join拼接的,当循环td的时候会产生一个空串,界面就会出现一个逗号, 虽然功能块算实现了,不过始终美中不足,然后想到的办法是替换所 ...

  9. Android环境搭建的步骤

    Android 环境搭建步骤 这里简单介绍一下学习Android之后如何搭建环境的问题 一.    在搭建环境之前,首先你要先下载Java JDK(根据系统位数选择下载是64位或32位的),Eclip ...

  10. SignalR 2.0入门

    下载已完成的项目 本教程展示如何使用那么 SignalR 创建一个实时聊天应用程序.你会那么 SignalR 添加一个空的 ASP.NET web 应用程序,创建一个 HTML 页面发送并显示消息. ...