How to get user properties like created by in sas - sas

How to fetch user details for a .sas file or file properties for all files stored in a directory? I am trying to get all possible attributes like: modified date, modified by, created by, for a macro.
data dir_meta(drop=rc file_ref fid);
%let directory_ref = %sysfunc(filename(dirref,&dir));
%let dir_id=%sysfunc(dopen(&dirref));
if &dir_id eq 0 then do;
put _error_=1;
return;
end;
%let _count=%sysfunc(dnum(&dir_id);
do i=1 to &_count;
%let dir_name = %sysfunc(dread(&dir_id,&i);
if upcase(scan(&dir_name,-1,.)) = upcase(&extn) then do;
put &dir\&dir_name;
file_ref='temp';
file_name=%sysfunc( filename(file_ref,"&dir\&&dir_name"));
fid=%sysfunc(fopen(file_ref));
create_date=%sysfunc(finfo(&fid,Create Time));
Modified_date=%sysfunc(finfo(&fid,Last Modified));
output;
rc=fclose(fid);
end;
end;
%let rc_dir=%sysfunc(dclose(dir_id);
run;

Sweta,
Presuming you are using SAS in a recent version of Windows and the session has X command allowed, then you can pipe the results of a powershell command to a data step to read in what ever information you want.
In powershell use this command to see the kinds of information about a file that can be selected
PS > DIR | GET-MEMBER
Once you decide on the members to select a data step can read the powershell output. For example:
filename fileinfo pipe 'powershell -command "dir | select Fullname, Length, #{E={$_.LastWriteTime.ToString(''yyyy-MM-ddTHH:mm:ss.ffffffzzz'')}} | convertTo-csv"';
* powershell datetime formatting tips: https://technet.microsoft.com/en-us/library/ee692801.aspx?f=255&MSPPError=-2147217396;
data mydata;
infile fileinfo missover firstobs=4 dsd dlm=',';
attrib
filename length=$250
size length=8 format=comma12.
lastwrite length=8 format=datetime20. informat=E8601DZ32.6
;
input filename size lastwrite;
run;

Related

SAS filepath with variable parts

I am trying to iterate over a list of different files and input them.
DO Year = 2000 to 2021 by 1;
filename fileftp ftp year+'.csv.gz' host='ftp.abcgov'
cd='/pub/' user='anonymous'
pass='XXXX' passive recfm=s debug;
INFILE fileftp NBYTE=n;
END;
How do I get it so that year is included in the file name?
Currently, when I try this (year+'.csv.gz') it is trying to recognize year as an option incorrectly.
You need to use the SAS macro facility for this. Since your file is zipped, you'll also need to unzip it before importing the data.
%macro importData;
%do year = 2000 to 2021;
filename fileftp ftp "&year..csv.gz"
host = 'ftp.abcgov'
cd = '/pub/'
user = 'anonymous'
pass = 'XXXX'
recfm = s
passive
debug
;
filename download temp;
/* Download the file to a temporary local space */
%let rc = %sysfunc(fcopy(fileftp, download));
/* Unzip the file */
filename unzip "%sysfunc(pathname(download))" gzip;
/* Read the data and output it by year */
proc import
file = unzip
out = want&year.
dbms = csv
replace;
run;
%end;
%mend;
%importData;
If fcopy does not work for you, you can use a data step to write one file to another.
data _null_;
infile fileftp;
file download;
input;
put _INFILE_ ;
run;

how to read files from a folder that were created before a date

I am trying to use SAS to read multiple files from a directory and they were created before a date.
I have used this code to help me to read all the files. It works perfectly. Now I found out that only some files that were created before a certain date are what I need. I think that could be done either by FILENAME PIPE Dir options or by INFILE statement options, but I cannot find the answers.
code source:
http://support.sas.com/kb/41/880.html
filename DIRLIST pipe 'dir "C:\_today\file*.csv" /b ';
data dirlist ;
infile dirlist lrecl=200 truncover;
input file_name $100.;
run;
data _null_;
set dirlist end=end;
count+1;
call symputx('read'||put(count,4.-l),cats('c:\_today\',file_name));
call symputx('dset'||put(count,4.-l),scan(file_name,1,'.'));
if end then call symputx('max',count);
run;
options mprint symbolgen;
%macro readin;
%do i=1 %to &max;
data &&dset&i;
infile "&&read&i" lrecl=1000 truncover dsd;
input var1 $ var2 $ var3 $;
run;
%end;
%mend readin;
%readin;
Currently you are reading in just the file names using the dir command. The existing /b modifier is saying print just the file name and nothing else. You want to change it to read both the file name and the CREATED date of the file. In order to do that it gets a little messy. You will need to change that pipe command from:
filename DIRLIST pipe 'dir "C:\_today\file*.csv" /b ';
...to this... :
filename DIRLIST pipe 'dir "C:\_today\file*.csv" /tc ';
The output will change from something like this:
file1.csv
file2.csv
...
...to something like this... :
Volume in drive C has no label.
Volume Serial Number is 90ED-A122
Directory of C:\_today
01/13/2017 09:14 AM 1,991 file1.csv
01/11/2017 11:43 AM 169 file2.csv
...
...
...
01/11/2017 11:43 AM 169 file99.csv
99 File(s) 6,449 bytes
0 Dir(s) 57,999,806,464 bytes free
So you will then need to modify your data step that creates dirlist to clean up the results returned by the new dir statement. You will need to ignore the header and footer and read in the date and time etc. Once you have that date and time in the appropriate SAS format, you can then just use a SAS where clause to keep the rows you are interested in. I will leave this as an exercise for you to do. If you have trouble with it you can always open a new question.
If you need more information on the dir command, you can open up a command prompt (Start Menu->Run->"cmd"), and then type in dir /? to see a list of available switches for the dir command. You may find a slightly different combination of switches for it that better suits your task than what I listed above.
You can use powershell to leverage the features of the operating system.
filename get_them pipe
" powershell -command
""
dir c:\temp
| where {$_.LastWriteTime -gt '3/19/2019'}
| select -property name
| ft -hidetableheader
""
";
data _null_;
infile get_them;
input;
putlog _infile_;
run;

How to check available disk space using SAS

How can I check the space left on a drive and if it is less than 1GB to output a message using SAS.
I only have a code that checks the SAS file size.
I've basically modified the code available in this link according to your requirement. I've also added a bit of code to fix issues faced due to quotes and the pipe command. Basically you should let SAS deal with quotes before passing on the code.
%macro windows_bytes_free(sm_path);
%global mv_bytes_free;
%let mv_bytes_free = -1; /* In case of error */
%let filepath = %sysfunc(quote(%qsysfunc(dequote(&sm_path)))); /* To prevent issues with quotes remove quotes if present and apply it again*/
/* Run the DIR command and retrieve results using an unnamed pipe */
filename tempdir pipe %sysfunc(quote(dir /-c &filepath | find "bytes free")) ;
data _null_;
infile tempdir length=reclen ;
input line $varying1024. reclen ;
re = prxparse('/([0-9]+) bytes/'); /* Parse the output of DIR using a Perl regular expression */
if prxmatch(re, line) then do;
bytes_str = prxposn(re, 1, line);
bytes = input(bytes_str, 20.);
call symput('mv_bytes_free', bytes); /* Assign available disk space in bytes to a global macro variable */
kb = bytes /1024;
mb = kb / 1024;
gb = mb / 1024;
format bytes comma20.0;
format kb mb gb comma20.1;
/* Write a note to the SAS log */
put "NOTE: &sm_path " bytes= kb= mb= gb=;
if gb<1 then put '** Available space is less than 1 gb';
else put '** Enough space is available';
end;
run;
%if &mv_bytes_free eq -1 %then %put ERROR: error in windows_bytes_free macro;
%mend;
An example of how to use this macro for the C: drive
%windows_bytes_free(c:);
Tazz:
Presuming you are running SAS on a Windows platform -- Piping wmic command output into SAS can deliver vast amounts of information about the system, including the freespace on the disks.
WMIC - Using Windows Management Instrumentation Command-line;
https://msdn.microsoft.com/en-us/library/aa394531(v=vs.85).aspx;
%let csvdata = %sysfunc(pathname(work))\wmic_output.csv;
filename wmic_csv "&csvdata" encoding="utf-16";
filename gather pipe "wmic logicaldisk get name,size,freespace /format:csv";
* process the wmic command and strip off blank first row and extraneous CR character at end of line;
data _null_;
infile gather;
input;
if _n_ > 1;
_infile_ = compress(_infile_, '0d'x);
file wmic_csv;
put _infile_;
run;
proc import replace out=diskinfo file=wmic_csv dbms=csv;
run;
data _null_;
set diskinfo;
if freespace < 1e9 then put "WARNING: " name "has remaining" freespace=;
run;
wmic can also export it's information in XML format -- the output is more complicated but extremely capable. This sample code uses SAS' xmlv2 engine and the automap= option:
* WMIC - Using Windows Management Instrumentation Command-line;
* https://msdn.microsoft.com/en-us/library/aa394531(v=vs.85).aspx;
%let xmldata = %sysfunc(pathname(work))\wmic_output.xml;
%let xmlautomap = %sysfunc(pathname(work))\wmic_output-automap.xml;
%let xmlmap = %sysfunc(pathname(work))\wmic_output-map.xml;
filename wmic "&xmldata" encoding="utf-16";
filename wmicmap "&xmlmap";
filename gather pipe "wmic logicaldisk get name,size,freespace /format:rawxml > ""&xmldata""";
data _null_;
infile gather;
input;
put _infile_;
rc = sleep(.1,1);
run;
libname wmic xmlv2 automap=replace xmlmap=wmicmap;
proc copy in=wmic out=work;
run;
proc transpose data=work.property out=properties(drop=_name_) suffix=_text;
by instance_ordinal;
id property_name;
var value;
run;
filename gather;
filename wmic;
filename wmicmap;

sas macro to read multiple multsheet excel in folder

this is my code to read multiple multisheet excel in sas its giving an error which i am attaching in last.i am only reading first sheet named summary of every excel in that particular folder
%macro sks2sas01(input=d:\excels,out=work.tt);
/* read files in directory */
%let dir=%str(%'dir %")&input.%str(\%" /A-D/B/ON%');
filename myfiles pipe %unquote(&dir);
data list1; length fname $256.;
infile myfiles truncover;
input myfiles $100.;
/* put _infile_;*/
fname=quote(upcase(cats("&input",'\',myfiles)));
out="&out";
drop myfiles;
call execute('
PROC IMPORT DBMS=EXCEL2002 OUT= _1
DATAFILE= '||fname||' REPLACE ;
sheet="summary";
RUN;
proc append data=_1 base='||out||' force; run;
proc delete data=_1; run;
');
run;
filename myfiles clear;
%mend sks2sas01;
%sks2sas01(input=c:\sasupload\excels,out=work.tt);
hereby i am attaching error i am getting:
GOPTIONS ACCESSIBLE;
%macro sks2sas01(input=d:\excels,out=work.tt);
/* read files in directory */
%let dir=%str(%'dir %")&input.%str(\%" /A-D/B/ON%');
filename myfiles pipe %unquote(&dir);
data list1; length fname $256.;
infile myfiles truncover;
input myfiles $100.;
/* put _infile_;*/
fname=quote(upcase(cats("&input",'\',myfiles)));
out="&out";
drop myfiles;
call execute('
PROC IMPORT DBMS=EXCEL2002 OUT= _1
DATAFILE= '||fname||' REPLACE ;
sheet="summary";
RUN;
proc append data=_1 base='||out||' force; run;
proc delete data=_1; run;
');
run;
filename myfiles clear;
%mend sks2sas01;
%sks2sas01(input=c:\sasupload\excels,out=work.tt);
ERROR: Insufficient authorization to access PIPE.
ERROR: Error in the FILENAME statement.
I had this exact same problem the other day. I had no authorization for the pipe command, and dir using sftp wasn't working for me either. This alternative solution worked great for me. In a nutshell, you're going to use some oldschool SAS directory commands to read every file within that directory, and save only the ones that end in .xlsx.
You can consider the name of your Excel files .-delimited, scan the filename of each one backwards, and look at just the first word to obtain only those Excel files. For example:
File name.xlsx
Backwards:
Delimiter
v
xlsx.name File
^^^^
First word
Step 1: Read all XLSX files in the directory, and create a dataset of them
filename dir 'C:\MyDirectory';
data XLSX_Files;
DirID = dopen("dir");
do i = 1 to dnum(DirID);
file_name = dread(DirID, i);
if(upcase(scan(file_name, 1, '.', 'b') ) = 'XLSX') then output;
end;
rc=dclose(DirID);
drop i rc DirID;
run;
Step 2: Read all of those names into a pipe-delimited macro variable
proc sql noprint;
select file_name, count(file_name)
into :XLSX_Files separated by '|',
:tot_files
from XLSX_Files;
quit;
Step 3: Import them all in a macro loop
%macro import_all;
%do i = 1 %to &tot_files;
proc import file="C:\MyDirectory\%scan(&XLSX_Files,&i,|)"
out=XLSX_&i
dbms=xlsx replace;
run;
%end;
%mend;
%import_all;
You can then stack or merge them as you need.
data Master_File;
set XLSX_1-XLSX_&tot_files;
run;
OR
data Master_File;
merge XLSX_1-XLSX_&tot_files;
by key;
run;

SAS Export data to create standard and comma-delimited raw data files

i m new to sas and studying different ways to do subject line task.
Here is two ways i knew at the moment
Method1: file statement in data step
*DATA _NULL_ / FILE / PUT ;
data _null_;
set engappeal;
file 'C:\Users\1502911\Desktop\exportdata.txt' dlm=',';
put id $ name $ semester scoreEng;
run;
Method2: Proc Export
proc export
data = engappeal
outfile = 'C:\Users\1502911\Desktop\exportdata2.txt'
dbms = dlm;
delimiter = ',';
run;
Question:
1, Is there any alternative way to export raw data files
2, Is it possible to export the header also using the data step method 1
You can also make use of ODS
ods listing file="C:\Users\1502911\Desktop\exportdata3.txt";
proc print data=engappeal noobs;
run;
ods listing close;
You need to use the DSD option on the FILE statement to make sure that delimiters are properly quoted and missing values are not represented by spaces. Make sure you set your record length long enough, including delimiters and inserted quotes. Don't worry about setting it too long as the lines are variable length.
You can use CALL VNEXT to find and output the names. The LINK statement is so the loop is later in the data step to prevent __NAME__ from being included in the (_ALL_) variable list.
data _null_;
set sashelp.class ;
file 'class.csv' dsd dlm=',' lrecl=1000000 ;
if _n_ eq 1 then link names;
put (_all_) (:);
return;
names:
length __name__ $32;
do while(1);
call vnext(__name__);
if upcase(__name__) eq '__NAME__' then leave;
put __name__ #;
end;
put;
return;
run;