†REXXのどろぬま†

REXXによるFTPサーバへのアクセス

作成開始日 2010.03.11
最終更新日 2021.01.09

[アシスタンス・センター|情報]の中にREXX FTP APIの解説書があるので、それを読めば使い方は判る。以下、基本的な処理の流れを簡単に。
/*** REXXのFTP APIを読み込む***/
rc = RxFuncAdd("FtpLoadFuncs","rxFtp","FtpLoadFuncs")
rc = FtpLoadFuncs()

/* ftpサーバに接続(ホスト名、ユーザー名、パスワードの順)*/
rc = FtpSetUser('ftp.xxxx.yyyy.zzz.ne.jp','my-name','xxxxxxx');

/* 転送モードをバイナリに設定(テキストでもこの方が良い)*/
rc = FtpSetBinary('Binary');

/* サーバ上のファイル一覧、日付情報などの取得 */
/* 例)サーバ上の「/html/os2」ディレクトリにある「*.htm」ファイルの一覧 */
rc = FtpDir('/html/os2/*.htm','file.')
do n=1 to file.0
  say file.n
end

/* ftpサーバにディレクトリを作成する */
/* 例)サーバ上の「/html」の中に「/video」というディレクトリを作成する */
rc = FtpMkDir('/html/video')

/* ファイルをサーバにアップする*/
/* 例)ローカルにある「index.htm」をサーバ上の「/html/video/」にコピーする */
/* 注意)コピー先はディレクトリ名だけでなく、ファイル名必須 */
rc = FtpPut('index.htm', '/html/video/index.htm');

/* ログオフ */
rc = FtpLogoff();

/* エラーの確認(各コマンドの実行後) */
if rc=-1 then say '*** エラー発生' FTPERRNO

●タイムスタンプの問題

FtpDirで得られるタイムスタンプの形式はDOS系とは異なるので注意(Hi-HOの場合)。

種類形式用例
1年以内のタイムスタンプ月(英字3文字) 日 時:分(24h表示)Mar 11 20:45
1年以前のタイムスタンプ月(英字3文字) 日 年(4桁)Jul 7 2017

この形式ではタイムスタンプの新旧比較が非常に面倒。具体的な処理方法は後述のサンプル2を参照。

なお、ftpサーバ上のファイルのタイムスタンプは、元ファイルの日付ではなく、アップロードの日付となる。元ファイルの更新日付が必要な場合は、別の方法で管理するしかない。アップロード元が1つだけなら、ローカルとリモートのファイル日付の比較だけで新旧の判別は可能だが、厄介なのは、複数の場所から更新処理をする場合。以前は、元のタイムスタンプの一覧ファイルを作成していた。個人的には、仕事場を一つに絞ったので、その必要はなくなったけれど…

●サンプル1:指定したファイルをアップロードする(ワイルドカード可)

/*********************************************************************/
/* ftp uploader                                                      */
/*********************************************************************/
Call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
Call SysLoadFuncs
rc = RxFuncAdd("FtpLoadFuncs","rxFtp","FtpLoadFuncs")
rc = FtpLoadFuncs()

mask=arg(1)		/* ワイルドカード指定可能 */

/* サーバ名、ユーザー名、パスワードを指定 */
rc = FtpSetUser('ftp.xxxx.yyyy.zzz.ne.jp','my-name','xxxxxxx');
if rc=-1 then say '*** エラー' ftperrno
rc = FtpSetBinary("Binary");

rc=sysfiletree(mask,'f.',FO)
do n=1 to f.0
  /* ローカルファイル名からリモートファイル名を作成する */
  /* ローカルとリモートのディレクトリ構造が一致していることが前提 */
  /* たとえば、ローカル=d:\myhp\html\book\、リモート=/html/book/  */
  remoteFname=translate(f.n,'/','\')
  remoteFname=substr(remoteFname,9) /* ここは各自の環境に合わせて変更 */

  /* ftpサーバ側に当該ディレクトリがあるか確認し、なければ作成する */
  remoteDir=FileSpec('P',remoteFname)
  rc = FtpDir(remoteDir, 'd.');
  if d.0=0 then
  do
    say '*** MAKE DIRECTORY :' remoteDir
    say
    rc=FtpMkDir(remoteDir)
    if rc=-1 then say '*** エラー' ftperrno
  end

  /* ファイルをアップロードする */
  say remoteFname
  rc = FtpPut(f.n, remoteFname);
  if rc=-1 then say '*** エラー' ftperrno
end
rc = FtpLogoff();

EXIT

●サンプル2:ローカルにサーバよりも新しいファイルがあれば自動更新する(新規追加はなし)

/*********************************************************************/
/* ftp update uploader 2018.03.11-2021.01.09  (c) suikodow           */
/* 更新専用:サーバ上に同名ファイルがない場合は、日付に拘らずアップしない*/
/* 機能追加:/n オプションで新規ファイルをアップロード(2020.01.09)       */
/* バグ修正:年またぎで1年以内の場合の日付形式の変換のバグ(2021.01.09)   */
/*********************************************************************/
Call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
Call SysLoadFuncs
Call RxFuncAdd 'FtpLoadFuncs','rxFtp','FtpLoadFuncs'
Call FtpLoadFuncs
NUMERIC DIGITS 14	/* 有効桁数14桁:日時比較用*/

SAY '---------------------------------------------------------'
SAY 'fud -- ftp update uploader ver.0.1  2018.03.11 suikodow'
SAY '---------------------------------------------------------'

opt=arg(1)
if opt='/n' then flgNew=1; else flgNew=0

y0=left(date('S'),4)		/* 今年の年   例)2021 */
d0=substr(date('S'),5,4)	/* 今日の月日 例) 0109 */

/* ローカル&リモートのディレクトリを設定 */
curdir=directory();
remdir=substr(translate(curdir,'/','\'),9)

/* ローカルファイルの一覧と日時情報の取得 */
rc=sysfiletree(curdir'\*.*',lf.,'FT')
do n=1 to lf.0
  parse var lf.n yy'/'mm'/'dd'/'hh'/'mn dmy dmy fname
  dt=20||yy||mm||dd||hh||mn
  lf.n=dt' 'filespec('N',fname)
end

/* リモートファイルの一覧と日付情報の取得 */
rc=FtpSetUser('ftp.xxx.yyy.zzz.com','myuserid','mypassword');
if rc=-1 then say '*** エラー' ftperrno
rc=FtpSetBinary('Binary');
rc=FtpDir(remdir,rf.)

do n=1 to rf.0
  /* xxは「年(例 2018)」か「時分(例 18:32)」 */
  parse var rf.n dmy dmy dmy dmy dmy mm dd xx fname

  /* 月を英字表記から数字表記に変換 */
  mm=wordpos(mm,'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec')
  mm=right('0'||mm,2)
  dd=right('0'||dd,2)
  d1=mm||dd	/* リモートの日付(年なし) 例) 1205 / 後で使用する */

  /* 時分か年かを判別して処理 */
  if pos(':',xx)>0 then
  Do
    parse var xx hh':'mn
    hh=right('0'||hh,2)
    mn=right('0'||mn,2)
    if d1>d0 then  yy=y0-1; else yy=y0	/* 今日から1年以上前か否か */
  End
  Else do
    hh=23
    mn=59
    yy=xx
  End

  rf.n=yy||mm||dd||hh||mn fname
end

/* 存否確認と新旧比較をして更新分をアップロード */
Do n=1 to lf.0
  parse var lf.n ldt lname
  Do m=1 to rf.0
    parse var rf.m rdt rname
    /* if (lname=rname) then say rname 'local='ldt 'remote='rdt 'd='ldt-rdt */
    if (lname=rname)&(ldt>rdt) then
    Do
      say lname '( update :' dtform(rdt) '-->' dtform(ldt) ')'
      rc=FtpPut(lname, remdir'/'rname)
      if rc=-1 then say '*** エラー' ftperrno
    End
  End
End

/* 新規ファイルのアップロード(オプション) */
if flgNew=1 then
Do
  Do n=1 to lf.0
    flgSame=0
    parse var lf.n ldt lname
    Do m=1 to rf.0
      parse var rf.m rdt rname
      if lname=rname then flgSame=1
    End
    if flgSame=0 then
    Do
      say lname '( newfile :' dtform(ldt) ')'
      rc=FtpPut(lname, remdir'/'lname)
      if rc=-1 then say '*** エラー' ftperrno
    End
  End
End

rc=FtpLogoff();

exit

/*-------------------------------------------------------------------*/
dtform : Procedure
dt=arg(1)
yy=left(dt,4)
mm=substr(dt,5,2)
dd=substr(dt,7,2)
hh=substr(dt,9,2)
mn=substr(dt,11,2)
return yy'/'mm'/'dd'@'hh':'mn


【REXXのどろぬま目次】 【ホーム】