原文地址:SAS编程技巧--获取给定目录下文件信息的宏作者:hhshnsq
有人在StackOverflow上提问:提问者写了一个SAS宏来获取给定目录下的文件信息,但是代码处理带空格的目录时出错,发帖请求他人的帮助。虽然这是一个很小的功能,但是从回答者的代码可以看到广大SAS程序员的编程功底。
原帖地址:http://stackoverflow.com/questions/1409543/using-sas-macro-to-pipe-a-list-of-filenames-from-a-windows-directory
本人将帖子中的五种实现方法总结如下,并对各种方法加以点评。这个帖子绝对值得一读,尤其是代码里对SAS宏变量中引号的各种处理方法。
方法一:通过SAS提供的文件操作函数 dopen、dnum、dread、dclose。
%macro get_filenames(location);
filename _dir_ "%bquote(&location.)";
data filenames(keep=memname);
handle=dopen( '_dir_' );
if handle > 0 then do;
count=dnum(handle);
do i=1 to count;
memname=dread(handle,i);
output filenames;
end;
end;
rc=dclose(handle);
run;
filename _dir_ clear;
%mend;
%get_filenames(C:temp);
%get_filenames(C:tempwith space);
%get_filenames(%bquote(C:tempwith'singlequote));
点评:
能够处理路径中包含空格、单引号等特殊命名的情况;
代码可在各种操作系统上运行。
方法二:通过管道技术实现
%macro get_filenames(location); %*--(1)--*;
filename pipedir pipe "dir ""%unquote(&location)"" /b" lrecl=32767; %*--(2)--*;
data filenames;
infile pipedir truncover;
input filename $char1000.;
put filename=;
run;
filename pipedir clear; %*--(3)--*;
%mend;
点评:
能够处理路径中包含空格、单引号等特殊命名的情况;
有些操作系统不支持管道。
方法三:通过管道技术实现
%macro DirList(dir);
filename dirpipe pipe "dir ""%unquote(&dir)""*.* /s /-c";
data dir_list(label="Directory Listing [&DIR.]" drop=re_: _line_ date time);
format Path
File $250.
ModDT datetime19.
Size 16.
_line_ $32000. ;
if _N_ = 1 then do;
re_path=prxparse("/Directory of (.+)/");
re_subd=prxparse("/(dd/dd/dddd)s+(dd:dd [A|P]M)s+s+(S.*)/");
re_file=prxparse("/(dd/dd/dddd)s+(dd:dd [A|P]M)s+(d+)s+(S.*)/");
retain re_: path;
end;
infile dirpipe lrecl=32000; input; _line_ = _infile_;
if lengthn(_line_)=0 then delete;
else
if prxmatch(re_path, _line_) then do;
path=prxposn(re_path, 1, _line_);
end;
else
if prxmatch(re_subd, _line_) then do;
date=input(prxposn(re_subd, 1, _line_), mmddyy10.);
time=input(prxposn(re_subd, 2, _line_), time6.);
ModDT=dhms(date, 0, 0, time);
File=prxposn(re_subd, 3, _line_);
size = .D;
if file not in ('.', '..') then output;
end;
else
if prxmatch(re_file, _line_) then do;
date=input(prxposn(re_file, 1, _line_), mmddyy10.);
time=input(prxposn(re_file, 2, _line_), time6.);
ModDT=dhms(date, 0, 0, time);
size=input(prxposn(re_file, 3, _line_), 16.);
file=prxposn(re_file, 4, _line_);
output;
end;
run;
filename dirpipe clear;
%mend;
点评:
能够处理路径中包含空格、单引号等特殊命名的情况;
能够获取该目录及其子目录下所有文件的信息;
有些操作系统不支持管道;
不同操作系统下dir命令执行结果的格式不同,正则表达式需要修改。
方法四:通过SAS SYSTEM函数执行操作系统命令
注意一定要将 NOXWAIT 和 XSYNC 选项打开。
%macro getdir(dir=,redirect=, switch=);
options noxwait xsync;
%if %length(&switch)=0 %then %let switch=b;
data _null_;
xcmd='dir "' || "&dir" || '"' || "/&switch " || ">" || "&redirect";
put 'generated the following command: ' xcmd=;
rc=system(xcmd);
put 'result code of above command: ' rc=;
run;
%mend getdir;
点评:
能够处理路径中包含空格、单引号等特殊命名的情况;
功能比较简单,不如其他方法强大。
方法五:通过SAS提供的文件操作函数 dopen、dnum、dread、dclose。
%macro isDir(iPath=,iQuiet=1);
%local result dname;
%let result = 0;
%if %sysfunc(filename(dname,&iPath)) eq 0 %then %do;
%if %sysfunc(dopen(&dname)) %then %do;
%let result = 1;
%end;
%else %if not &iQuiet %then %do;
%put ERROR: ISDIR: %sysfunc(sysmsg());
%end;
%end;
%else %if not &iQuiet %then %do;
%put ERROR: ISDIR: %sysfunc(sysmsg());
%end;
&result
%mend;
%put %isDir(iPath=&sasdir/common/macros);
%put %isDir(iPath=&sasdir/kxjfdkebnefe);
%put %isDir(iPath=&sasdir/kxjfdkebnefe, iQuiet=0);
%put %isDir(iPath=c:temp);
%macro file_list(iPath=, iFilter=, iFiles_only=0, iDelimiter=|);
%local result did dname cnt num_members filename;
%let result=;
%if %sysfunc(filename(dname,&iPath)) eq 0 %then %do;
%let did = %sysfunc(dopen(&dname));
%let num_members = %sysfunc(dnum(&did));
%do cnt=1 %to &num_members;
%let filename = %sysfunc(dread(&did,&cnt));
%if "&filename" ne "" %then %do;
%if &iFiles_only %then %do;
%if not %isDir(iPath=&iPath/&filename) %then %do;
%if "&iFilter" ne "" %then %do;
%if %index(%lowcase(&filename),%lowcase(&iFilter)) %then %do;
%let result = &result%str(&iDelimiter)&filename;
%end;
%end;
%else %do;
%let result = &result%str(&iDelimiter)&filename;
%end;
%end;
%end;
%else %do;
%if "&iFilter" ne "" %then %do;
%if %index(%lowcase(&filename),%lowcase(&iFilter)) %then %do;
%let result = &result%str(&iDelimiter)&filename;
%end;
%end;
%else %do;
%let result = &result%str(&iDelimiter)&filename;
%end;
%end;
%end;
%else %do;
%put ERROR: (CMN_MAC.FILE_LIST) FILE CANNOT BE READ.;
%put %sysfunc(sysmsg());
%end;
%end;
%end;
%else %do;
%put ERROR: (CMN_MAC.FILE_LIST) PATH DOES NOT EXIST OR CANNOT BE OPENED.;
%put %sysfunc(sysmsg());
%end;
%if "&result" ne "" %then %do;
%substr(&result,2)
%end;
%mend;
**
** EXAMPLES - HAVENT TESTED THE LAST TWO YET BUT THEY SHOULD WORK IF SYNTAX IS CORRECT
*;
%put %file_list(iPath=c:temp);
%put %file_list(iPath=c:xxdffsds);
%put %file_list(iPath=c:robSASDev, iFilter=a);
%put %file_list(iPath=c:robSASDev,iFiles_only=1);
%put %file_list(iPath=/tmp/unix_sasdir,iFiles_only=1);
data x;
file_list = "%file_list(iPath=c:temp)";
run;
proc sql noprint;
insert into my_table values ("%file_list(iPath=c:temp,iDelimiter=%str(","))");
quit;
点评:
能够处理路径中包含空格、单引号等特殊命名的情况;
代码可在各种操作系统上运行;
有完备的错误检查,良好的编程规范,代码值得学习。