Discussion:
SAS Code to retrieve File/Directory Details
(too old to reply)
Ernie P.
2009-08-25 21:26:01 UTC
Permalink
Hi,

I was wondering if there is a way in SAS to get directory/file information
such as size, last modified date, creation date, etc. I would like to do
this for all files in a directory, not just sas datasets, so PROC
CONTENTS/DATASETS would not be sufficient.

I could open up a command prompt via SAS, use the DIR command to send this
type of information a text file, and then read this file into SAS. But I
would like to not use the command prompt from SAS.

Any ideas?

Thanks,

Ernie P.
Etaoin
2009-08-25 22:36:53 UTC
Permalink
Hi Ernie:

%let currdir= %str(C:\Desktop\Misc);

%let fref=%unquote(%str(%')dir /Q %str(%")&currdir.\*.* %str(%")%str
(%'));

filename allfil pipe &fref.;

data test;
length v1 v2 v3 v4 owner filnam $100;
infile allfil truncover end=eof;
input v1 v2 v3 v4 owner filnam;
run;


The above code gets the info directly into a SAS dataset (although you
might want to do some data cleaning). What kind of file info you
require might depend upon the DOS command specified in the 'fref'
macro variable.

HTH
GD
Post by Ernie P.
Hi,
I was wondering if there is a way in SAS to get directory/file information
such as size, last modified date, creation date, etc.  I would like to do
this for all files in a directory, not just sas datasets, so PROC
CONTENTS/DATASETS would not be sufficient.
I could open up a command prompt via SAS, use the DIR command to send this
type of information a text file, and then read this file into SAS.  But I
would like to not use the command prompt from SAS.
Any ideas?
Thanks,
Ernie P.
Arthur Tabachneck
2009-08-25 22:00:01 UTC
Permalink
Ernie,

There are a number of ways. Some are shown in the thread at:
http://xrl.us/bfeov6

I, personally, usually use a pipe to run the window's dir command.

HTH,
Art
---------
Post by Ernie P.
Hi,
I was wondering if there is a way in SAS to get directory/file information
such as size, last modified date, creation date, etc. I would like to do
this for all files in a directory, not just sas datasets, so PROC
CONTENTS/DATASETS would not be sufficient.
I could open up a command prompt via SAS, use the DIR command to send this
type of information a text file, and then read this file into SAS. But I
would like to not use the command prompt from SAS.
Any ideas?
Thanks,
Ernie P.
xlr82sas
2009-08-26 01:34:42 UTC
Permalink
Post by Arthur Tabachneck
Ernie,
There are a number of ways.  Some are shown in the thread at:http://xrl.us/bfeov6
I, personally, usually use a pipe to run the window's dir command.
HTH,
Art
---------
Post by Ernie P.
Hi,
I was wondering if there is a way in SAS to get directory/file information
such as size, last modified date, creation date, etc.  I would like to do
this for all files in a directory, not just sas datasets, so PROC
CONTENTS/DATASETS would not be sufficient.
I could open up a command prompt via SAS, use the DIR command to send this
type of information a text file, and then read this file into SAS.  But I
would like to not use the command prompt from SAS.
Any ideas?
Thanks,
Ernie P.- Hide quoted text -
- Show quoted text -
for a cleaner version of this post see

http://homepage.mac.com/magdelina/.Public/utl.html

later tonight (pacific time)

As a side note you can eliminate the 'Klingon' macro quoting issues
with judiucious use of %sysfunc quote and dequote.

Here is an example that some might feel simplifies quoting. Your
problem is a little more difficult than most because you need outside
single quotes, inside double quotes, and the evaluation of a maco
variable.

this
%let fref=%unquote(%str(%')dir /Q %str(%")&currdir.\*.* %str(%")%str
(%'));
becomes
%let frer=%sysfunc(quote('dir /Q "&currdir.\*.*"'));

It is even nastier on unix because of the /* in the filename.

This seems to work for your situation

%symdel frer;
%symdel currdir;
%let currdir= %str(C:\xls);
%let frer=%sysfunc(quote('dir /Q "&currdir.\*.*"'));

filename allfil pipe %sysfunc(dequote(&frer));
data test;
length v1 v2 v3 v4 owner filnam $100;
infile allfil truncover end=eof;
input v1 v2 v3 v4 owner filnam;
run;

NOTE: The infile ALLFIL is:
Unnamed Pipe Access Device,
PROCESS=dir /Q "C:\xls\*.*",RECFM=V,LRECL=256

NOTE: 27 records were read from the infile ALLFIL.
The minimum record length was 0.
The maximum record length was 90.
NOTE: The data set WORK.TEST has 27 observations and 6 variables.
NOTE: DATA statement used (Total process time):
real time 0.07 seconds
cpu time 0.00 seconds


================================================================================

Here are some other examples where quote and dequote can eliminate
some of the Klingon macro quoting.

data
test;
lookup_string_quo =
'''100%on''';
lookup_string_unq =
'100%on';
call symput( 'lookup_unq',
lookup_string_unq);
call symput( 'lookup_quo',
lookup_string_quo);

master_string='100%on';
run;

/* error
*/
proc sql;select * from test where index( master_string,
"&lookup_unq" ) > 0 ;quit;
/* no error
*/
proc sql;select * from test where index( master_string,
&lookup_quo ) > 0 ;quit;
/* klingon quoting
*/
proc sql;select * from test where index( master_string, "%superq
(lookup_unq)" ) > 0 ;quit;

/* we want delay the assignment of x and userid - may be another user
in the final routine */
%symdel
x;
%symdel
str;
%let str=%nrstr(%%)let x=%nrstr(%substr(&sysuserid,2))%str
(;);
%unquote
(&str);
%put
&x;
/* prints deangel
*/
/* why not
*/
%symdel
x;
%symdel
str;
%let str='%let x=%substr(&sysuserid,
2)';
%sysfunc(dequote
(&str));
%put
&x;
/* prints deangel
*/
Data _null_;
2009-08-27 15:00:27 UTC
Permalink
As a side note you can eliminate the 'Klingon' macro quoting > issues with judiucious use of %sysfunc quote and dequote.
Good point regarding QUOTE/DEQUOTE functions. Since this application
requires a data step you could avoid %SYSFUNC and the creation of
extra macro variable(s) altogether by moving more of the work to the
data step. You don't necessarily need a FILEREF created with a
FILENAME statement for example.

%let currdir = c:\docs; *user input;

data dir;
length command $256;
command = catx(' ','dir /Q/S',quote(symget('currdir')));
infile dummy pipe filevar=command end=eof
length=length truncover;
do while(not eof);
input; *need code to read DIR info;
put _infile_;
end;
stop;
run;
xlr82sas
2009-08-27 18:18:16 UTC
Permalink
Post by Data _null_;
As a side note you can eliminate the 'Klingon' macro quoting > issues with judiucious use of  %sysfunc quote and dequote.
Good point regarding QUOTE/DEQUOTE functions. Since this application
requires a data step you could avoid %SYSFUNC and the creation of
extra macro variable(s) altogether by moving more of the work to the
data step.  You don't necessarily need a FILEREF created with a
FILENAME statement for example.
%let currdir = c:\docs; *user input;
data dir;
   length command $256;
   command = catx(' ','dir /Q/S',quote(symget('currdir')));
   infile dummy pipe filevar=command end=eof
        length=length truncover;
   do while(not eof);
      input;  *need code to read DIR info;
      put _infile_;
      end;
   stop;
   run;
Thanks Data Null

for a cleaner view of this see

http://homepage.mac.com/magdelina/.Public/utl.html
later tonight pacific time

Here are a few useful macros ( a have a package of 100 sysfunc macros
on my site for download - no collisions with SAS supplied macros)

%macro sysquote(arg1);
%sysfunc(quote(&arg1))
%mend sysquote;

%macro sysdequote(arg1);
%sysfunc(dequote(&arg1))
%mend sysdequotr;

%macro SysJustInTime
(arg1);
%sysfunc(dequote(%sysfunc(dequote(%sysfunc(quote(&arg1))))));
%mend
sysjustintime;

%let
inr=rdeangel;
%let txt='delayed the resolution of &inr &sysuserid %left(%trim
( FIXUP )) " just some quoting &sysver"';
/* many datsteps macros and lines of code */
%let res=%SysJustInTime
(&txt);
%put
res=&res;
res=delayed the resolution of rdeangel rdeangel FIXUP "just some
quoting 9.1"

A couple of points on quote/dequote

The beauty of sysfunc quote/dequote is the ability to delay macro
substitution and evaluation.I know SAS is not consistent in the
application of quoting and dequoting macro variables, especially with
regex and fread/fput when used with the macro facility. I think this
method simplifies some cases of macro quoting.

One point the quote function uses double quotes. This has two
functions, one it adds double quotes around the macro variable and
most importantly it evaluates the all macro triggers. Unfortunately
this may not be what you want to do,.so it does NOT eliminate the need
for selective quoting, ie quote '%' but not '&'.


Each morniing when I get up I say to myself

1. Use the datastep and FCMP to eliminate klingon macro variable
encantations and macros. I learned this lesson from Ian.
2. Most REPORTING many standard macros can be replaced with more
FLEXIBLE NON-MACRO 9.2 code.
I have been burned too many times by simple requests that 5,000
line STANDARD macros could not do(see below)
Here are some techniques to handle the MANY simple requests that
5,000 line STANDARD macros cannot. All in 30-60 lines of NON-MACRO code
(see my site for some details).
a. Normalize the data structures as soon as possble (make long
and skinny) ie (two columns -- Question Answer - like the Oracle
response table in Oracle Clinical)) ( I learned this from Howard)
b. Use ODS output (with match_all) and procedures like tabulate
to get N(PCT) and Univariate stats(Mean(SD) at once also use
preloadfmt and completypes. You are only interested in the ODS output
datasets. Not the report.
c. Use two formats to setup page location, order on page,
Major, Minor headings and mutiple indentations (with multilabel if
needed)
d Convert the the Answer colum to character with all the
formatting you need. Add rtf contols like superscripts. An answer
cell might contain Mean(SD) ie 97.1(99.11)\{super 1}
e. Transpose the long and skinny for consumption by proc report.
f Make sure options center and landscape ot portrait are se.
g. Male sure you set outputwidth in prepage and ods rtf text=
is in sync with your template.
e. Never use across or analysis varables in proc report. use
proc report like a dumb proc print. Run proc report for each page so
that you can have different footnotes on each page. (Use percent
cellwidths - never use fixed cellwidths)
f. Set up 100%, 75% and 50% width ods templates. Set
protectspecialchars to no for all style eliments. use
outputwidth=100% in style tabel. Many other template settings. I will
post some templates on my site.
g Build a custom png300 divice driver that honors you templates
and has an array of good hardware fonts.
I will post my png300 driver on my site.
i. Imbed graphcs in proc report(like excel does). Investigate the
new span and merge functions in proc report to create a 'box' within
proc report to place your '.png' graph. (see forrestplot code for a
pre 9.2 example)
Chang Chung
2009-08-28 20:59:54 UTC
Permalink
On Tue, 25 Aug 2009 17:26:01 -0400, Ernie P. <***@HOTMAIL.COM> wrote:
...
Post by Ernie P.
I was wondering if there is a way in SAS to get directory/file information
such as size, last modified date, creation date, etc. I would like to do
this for all files in a directory, not just sas datasets, so PROC
CONTENTS/DATASETS would not be sufficient.
I could open up a command prompt via SAS, use the DIR command to send this
type of information a text file, and then read this file into SAS. But I
would like to not use the command prompt from SAS.
Any ideas?
Hi, Ernie P.,

Found this gem in the proc fcmp manual http://tinyurl.com/msped5 or
http://support.sas.com/documentation/cdl/en/proc/61895/HTML/default/a0032627
33.htm

Ran successfully on my sas 9.2 TS lovel 1M0 on windows vista (32bit).

As it is, it just retrieves file name, but should not be too difficult to
modify it so that it retrieves other information using foptnum(),
foptname(), and finfo() functions once we get the file handle. Does anybody
want to try this?

Cheers,
Chang

proc fcmp outlib=work.func.dir;

function diropen(dir $);
length dir $ 256 fref $ 8;
rc = filename(fref, dir); /* fref is blank -- and it works?! yes */
if rc = 0 then do;
did = dopen(fref);
rc = filename(fref);
end;
else do;
msg = sysmsg();
put msg '(DIROPEN(' dir= ')';
did = .;
end;
return(did);
endsub;

subroutine dirclose(did);
outargs did;
rc = dclose(did);
did = .;
endsub;

subroutine dir_entries(dir $, files[*] $, n, trunc);
outargs files, n, trunc;
length dir entry $ 256;

if trunc then return;

did = diropen(dir);
if did <= 0 then return;

dnum = dnum(did);
do i = 1 to dnum;
entry = dread(did, i);
/* If this entry is a file, then add to array */
/* Else entry is a directory, recurse. */
fid = mopen(did, entry);
entry = trim(dir) || '\' || entry;
if fid > 0 then do;
rc = fclose(fid);
if n < dim(files) then do;
trunc = 0;
n = n + 1;
files[n] = entry;
end;
else do;
trunc = 1;
call dirclose(did);
return;
end;
end;
else
call dir_entries(entry, files, n, trunc);
end;

call dirclose(did);
return;
endsub;


run;

%let cmplib = %sysfunc(getoption(cmplib));
options cmplib = (work.func &cmplib);
data _null_;
array files[1000] $ 256 _temporary_;
dnum = 0;
trunc = 0;
call dir_entries("c:\", files, dnum, trunc);
if trunc then put 'ERROR: Not enough result array entries. Increase array
size.';
do i = 1 to dnum;
put files[i];
end;
run;
run;

options cmplib = (&cmplib);
xlr82sas
2009-08-29 02:18:18 UTC
Permalink
Post by Chang Chung
...
Post by Ernie P.
I was wondering if there is a way in SAS to get directory/file information
such as size, last modified date, creation date, etc.  I would like to do
this for all files in a directory, not just sas datasets, so PROC
CONTENTS/DATASETS would not be sufficient.
I could open up a command prompt via SAS, use the DIR command to send this
type of information a text file, and then read this file into SAS.  But I
would like to not use the command prompt from SAS.
Any ideas?
Hi, Ernie P.,
Found this gem in the proc fcmp manualhttp://tinyurl.com/msped5orhttp://support.sas.com/documentation/cdl/en/proc/61895/HTML/default/a...
33.htm
Ran successfully on my sas 9.2 TS lovel 1M0 on windows vista (32bit).
As it is, it just retrieves file name, but should not be too difficult to
modify it so that it retrieves other information using foptnum(),
foptname(), and finfo() functions once we get the file handle. Does anybody
want to try this?
Cheers,
Chang
proc fcmp outlib=work.func.dir;
function diropen(dir $);
   length dir $ 256 fref $ 8;
   rc = filename(fref, dir); /* fref is blank -- and it works?! yes */
   if rc = 0 then do;
      did = dopen(fref);
      rc = filename(fref);
   end;
   else do;
      msg = sysmsg();
      put msg '(DIROPEN(' dir= ')';
      did = .;
   end;
   return(did);
endsub;
subroutine dirclose(did);
   outargs did;
   rc = dclose(did);
   did = .;
endsub;
subroutine dir_entries(dir $, files[*] $, n, trunc);
   outargs files, n, trunc;
   length dir entry $ 256;
   if trunc then return;
   did = diropen(dir);
   if did <= 0 then return;
   dnum = dnum(did);
   do i = 1 to dnum;
      entry = dread(did, i);
      /* If this entry is a file, then add to array */
      /* Else entry is a directory, recurse. */
      fid = mopen(did, entry);
      entry = trim(dir) || '\' || entry;
      if fid > 0 then do;
         rc = fclose(fid);
         if n < dim(files) then do;
            trunc = 0;
            n = n + 1;
            files[n] = entry;
         end;
         else do;
            trunc = 1;
            call dirclose(did);
            return;
         end;
      end;
      else
         call dir_entries(entry, files, n, trunc);
   end;
   call dirclose(did);
   return;
endsub;
run;
%let cmplib = %sysfunc(getoption(cmplib));
options cmplib = (work.func &cmplib);
data _null_;
   array files[1000] $ 256 _temporary_;
   dnum = 0;
   trunc = 0;
   call dir_entries("c:\", files, dnum, trunc);
   if trunc then put 'ERROR: Not enough result array entries. Increase array
size.';
   do i = 1 to dnum;
      put files[i];
   end;
run;
run;
options cmplib = (&cmplib);
Thanks Chang,

You are opening a lot of new possibilities with FCMP.

I am experimenting with using FCMP fto call R(using sas 'javaobj') and
returning the inverse of a matrix.
Low overhead with Java much better than shelling out?

How about

data inverse;
array mat(2,2) ( 1 3 5 7);
array inv(2,2) ;
inv = inverse(mat); /* fcmp function inv using R engine
*/
run;
Ernie P.
2009-08-31 21:53:05 UTC
Permalink
All,

Thanks for the replies. As always, many great ideas were generated.


Ernie P.

Continue reading on narkive:
Loading...