Below macro read files from directory but i want to add code so it can read files from sub-directory
What can i do
%macro dir_contents(
dir= /* directory name to process */
, ext= /* optional extension to filter on */
, dsout=work.dir_contents /* dataset name to hold the file names */
, attribs=N /* get file attributes? (Y/N ) */
);
%global _dir_fileN;
%local _syspathdlim _exitmsg _attrib_vars;
%* verify the required parameter has been provided. ;
%if %length(&dir) = 0 %then %do;
%let _exitmsg = %str(E)RROR: No directory name specified - macro will exit.;
%goto finish;
%end;
%* verify existence of the requested directory name. ;
%if %sysfunc(fileexist(&dir)) = 0 %then %do;
%let _exitmsg = %str(E)RROR: Specified input location, &dir., does not exist - macro
will exit.;
%goto finish;
%end;
%* set the separator character needed for the full file path: ;
%* (backslash for Windows, forward slash for UNIX systems) ;
%if &sysscp = WIN %then %do;
%let _syspathdlim = \;
%end;
%else %do;
%let _syspathdlim = /;
%end;
/*--- begin data step to capture names of all file names found in the specified
directory. ---*/
data &dsout(keep=file_seq basefile pathname);
length basefile $ 40 pathname $ 1000 _msg $ 1000;
/* Allocate directory */
rc=FILENAME('xdir', "&dir");
if rc ne 0 then do;
_msg = "E" || 'RROR: Unable to assign fileref to specified directory. ' ||
sysmsg();
go to finish_datastep;
end;
/* Open directory */
dirid=DOPEN('xdir');
if dirid eq 0 then do;
_msg = "E" || 'RROR: Unable to open specified directory. ' || sysmsg();
go to finish_datastep;
end;
/* Get number of information items */
nfiles=DNUM(dirid);
do j = 1 to nfiles;
basefile = dread(dirid, j);
pathname=strip("&dir") || "&_syspathdlim." || strip(basefile);
%if %length(&ext) %then %do;
/* scan the final "word" of the full file name, delimited by dot character. */
ext = scan(basefile,-1,'.');
if ext="&ext." then do;
file_seq + 1;
output;
end;
%end;
%else %do;
file_seq + 1;
output;
%end;
end;
/* Close the directory */
rc=DCLOSE(dirid);
/* Deallocate the directory */
rc=FILENAME('xdir');
call symputx('_dir_fileN', file_seq);
finish_datastep:
if _msg ne ' ' then do;
call symput('_exitmsg', _msg);
end;
run;
%if %upcase(&attribs)=Y and &_dir_fileN > 0 %then %do;
data _file_attr(keep=file_seq basefile infoname infoval);
length infoname infoval $ 500;
set &dsout.;
/* open each file to get the additional attributes available. */
rc=filename("afile", pathname);
fid=fopen("afile");
/* return the number of system-dependent information items available for the
external file. */
infonum=foptnum(fid);
/* loop to get the name and value of each information item. */
do i=1 to infonum;
infoname=foptname(fid,i);
infoval=finfo(fid,infoname);
if upcase(infoname) ne 'FILENAME' then output;
end;
close=fclose(fid);
run;
/* transpose each information item into its own variable */
proc transpose data=_file_attr out=trans_attr(drop=_:) ;
by file_seq basefile ;
var infoval;
id infoname;
run;
proc sql noprint;
select distinct name into : _attrib_vars separated by ', '
from dictionary.columns
where memname='TRANS_ATTR' and upcase(name) not in('BASEFILE', 'FILE_SEQ')
order by varnum;
quit;
/* merge back the additional attributes to the related file name. */
data &dsout.;
merge &dsout. trans_attr;
by file_seq basefile;
run;
proc datasets nolist memtype=data lib=work;
delete _file_attr trans_attr;
run;
quit;
%end;
%if %length(&_exitmsg) = 0 %then
%let _exitmsg = NOTE: &dsout created with &_dir_fileN. file names ;
%if %length(&ext) %then
%let _exitmsg = &_exitmsg where extension is equal to &ext.;
%let _exitmsg = &_exitmsg from &dir..;
%finish:
%put &_exitmsg;
%if %length(&_attrib_vars) ne 0 %then %do;
%put;
%put NOTE: File attributes were requested and have been added to &dsout.. Variable
names are &_attrib_vars.;
%end;
%let _exitmsg = %str(E)RROR
if rc ne 0 then do; _msg = "E" || 'RROR: Unable to assign fileref to specified directory. ' || sysmsg();
?????? Why the %str? Why "E"|| 'RROR: ???
Suggest also looking at the CAT functions instead of || operator for concatenating
Crushing peanuts with an elephant's hoof. This can be achieved in a much simpler way by using the power of your operating system:
filename oscmd pipe "find /path -name \*.csv";
data _null_;
infile oscmd;
input;
call execute('%nrstr(%import_file(' !! strip(_infile_) !! '))');
run;
if you have a macro for importing a single file. Expand this step as needed.
%let _exitmsg = %str(E)RROR
if rc ne 0 then do; _msg = "E" || 'RROR: Unable to assign fileref to specified directory. ' || sysmsg();
?????? Why the %str? Why "E"|| 'RROR: ???
Suggest also looking at the CAT functions instead of || operator for concatenating
It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.