I have a code that is zipping files into one common file. It works by adding files into the zip folder and the code is provided below. But is there some simple way how to zip the whole folder, i.e. not file by file ?
/*path and files to be zipped*/
%let projectDir = C:\JJ\POKUS_II\data\;
filename newpdf "&projectDir./pokus.pdf";
filename newrtf "&projectDir./pokus.rtf";
filename newxlsx "&projectDir./pokus.xlsx";
/* Creating a ZIP file with ODS PACKAGE */
ods package(newzip) open nopf;
/*which files to zip*/
ods package(newzip) add file=newpdf;
ods package(newzip) add file=newrtf;
ods package(newzip) add file=newxlsx;
/*where to zip*/
ods package(newzip) publish archive
properties(
archive_name="archiv.zip"
archive_path="&projectDir."
);
ods package(newzip) close;
Thank you for suggestions which way to go.
It is possible without X command.
You have to read a catalog recursivly and add all files to the archive.
For some reason ods package it's very slow.
%let n=0;
%macro readCatalog(path, localpath);
%local rc _path filrf did noe filename fid i;
%if &localpath = %then
%let _path=&path;
%else
%let _path=&path\&localpath;
%let n=%eval(&n+1);
%let filrf=DIR&n;
%let rc = %sysfunc(filename(filrf, &_path));
%let did = %sysfunc(dopen(&filrf));
%let noe = %sysfunc(dnum(&did));
%do i = 1 %to &noe;
%let filename = %bquote(%sysfunc(dread(&did, &i)));
%let fid = %sysfunc(mopen(&did, &filename));
%if &fid > 0 %then %do;
%put &=path &=localpath &=_path &=filename;
ods package(newzip) add file="&_path\&filename" path="&localpath";
%end;
%else %do;
%if &localpath = %then
%readCatalog(&path, &filename);
%else
%readCatalog(&path, &localpath\&filename);
%end;
%end;
%let rc=%sysfunc(dclose(&did));
%mend readCatalog;
%macro createZIP(path, archive_name, archive_path);
%put *** Creating an archive (&archive_path\&archive_name) ***;
ods package(newzip) open nopf;
%readCatalog(&path)
ods package(newzip) publish archive properties(
archive_name="&archive_name"
archive_path="&archive_path"
);
ods package(newzip) close;
%mend createZIP;
%createZIP(C:\temp, test.zip, C:\temp2)
Related
I am trying to import all the CSV files in one folder and schedule the program in the SAS management console. Since it has empty CSV files in the folders, it failed to run the code automatically due to the errors. I was wondering if I can skip the steps of importing the empty file in the following codes.
`%macro drive(dir,ext);
%local cnt filrf rc did memcnt name;
%let cnt=0;
%let filrf=mydir;
%let rc=%sysfunc(filename(filrf,&dir));
%let did=%sysfunc(dopen(&filrf));
%if &did ne 0 %then %do;
%let memcnt=%sysfunc(dnum(&did));
%do i=0 %to &memcnt;
%let name=%qscan(%qsysfunc(dread(&did,&i)),-1,.);
%if %qupcase(%qsysfunc(dread(&did,&i))) ne %qupcase(&name) %then %do;
%if %superq(ext) = %superq(name) %then %do;
%let cnt=%eval(&cnt+1);
%put %qsysfunc(dread(&did,&i));
proc import datafile="&dir\%qsysfunc(dread(&did,&i))" out=dsn&cnt
dbms=csv replace;
guessingrows=max;
run;
data dsnnew&cnt (drop=old);set dsn&cnt (rename=(party_id = old)); party_id= input(old,12.);run;
%end;
%end;
%end;
%end;
%else %put &dir cannot be opened.;
%end;
%let rc=%sysfunc(dclose(&did));
%mend drive;`
PROC IMPORT cannot handle CSV files with fewer then 2 lines. You could just count how many lines the file has. No need to count beyond 2.
data _null_;
if eof then call symputx('nobs',_n_-1);
infile "&dir\%qsysfunc(dread(&did,&i))" obs=2 end=eof;
input;
run;
You can then test the value of the NOBS macro variable to decide whether or not to run PROC IMPORT>
%if &nobs>1 %then %do;
....
%end;
If the files all have the same structure then there is no need for the complicated macro code. Instead just read them all with one data step. You will have to write the code, but you will then have full control over how the variables are defined. You could include the actual name of the file as part of the dataset. Or perhaps extract some identifying information from the filename.
data want;
length fname filename $256 ;
infile "&dir/*.csv" filename=fname truncover dsd ;
input #;
* skip the header lines ;
if fname ne lag(fname) then delete;
* save the filename to a permanent variable;
filename=fname;
* Here is where you put the code to actually read the lines ;
input var1 var2 .... ;
run;
I use a macro in several SAS programs, so I defined it in a separate file /myFolder/myMacro.sas.
When running in batch, I want to use it this way: %include '/myFolder/myMacro.sas;'
When testing changes to the code in Enterprise Guide, I wan to edit and run /myFolder/myMacro.sas, then edit and run the programs that use it. How do I conditionally include the macro definitions?
%if &server = BATCH_SERVER %then %include '/myFolder/myMacro.sas;' does not work: The file is included anyway and the %if statement is applied to the comment on top of the file and results in
ERROR: Expected %DO not found.
ERROR: Skipping to next %END statement.
Just use a %then %do
%let mode=BATCH;
filename mac1 temp;
filename mac2 temp;
data _null_;
file mac1;
put '%macro mac1;%put mac1;%mend;%mac1;';
data _null_;
file mac2;
put '%macro mac2;%put mac2;%mend;%mac2';
run;
%if &mode=BATCH %then %do;
%inc mac2;
%end;
%else %do;
%inc mac1;
%end;
As I suspected, the error occurs because the include file starts with comments, somthing like:
* MyMacro is written to do this and that *;
* ************************************** *;
%macro MyMacro;
proc this;
proc that;
run;
%mend;
So after including the file, this becomes
%if &server = BATCH_SERVER %then * MyMacro is written to do this and that *;
* ************************************** *;
%macro MyMacro;
proc this;
proc that;
run;
%mend;
which is invalid.
When working inside a macro: add %do; and %end;
As Allan suggested, it is sufficient to put the %inlcude between %do; and %end;
%if &server = BATCH_SERVER %then %do;
%include '/myFolder/myMacro.sas;'
%end;
So after including the file, this becomes
%if &server = BATCH_SERVER %then %do;
* MyMacro is written to do this and that *;
* ************************************** *;
%macro MyMacro;
proc this;
proc that;
run;
%mend;
%end;
which works.
When working in open code: use call execute
data _null_;
if "&mode"="BATCH" then call execute ("%include /myFolder/myMacro.sas;");
run;
%DoIt;
I am running the following
%global source_dir util_dir paramf workdir datadir
dataunitid
saserror
;
%let datadir = %str(I:....\KATER\DATA);
%let outdir = %str(I:...\KATER\Results);
I set my library
libname datain "&datadir";
options mstored sasmstore=datain;
and then
%global liste_reg;
%let liste_reg=22 31;
%do k=1 %to %sysfunc(countw(&liste_reg.));
%let reg=%scan(&liste_reg.,&k.);
data hh_record; set datain.hh_record_®.; run;
data person_record; set datain.person_record_®.; run;
%let outdir_ = &outdir.\output_®.;
proc printto log = "&outdir_.Log.txt"; run;
But I get an error:
ERROR: File DATAIN.PERSON_RECORD_.DATA does not exist.
ERROR: File DATAIN.HH_RECORD_.DATA does not exist.
why is this happening, How can I put my data in datain library?
I am new in SAS so i am little confused. In general I realised that there is nothing in both libraries?
EDIT full code:
%global source_dir util_dir paramf workdir datadir
dataunitid
saserror
;
%let source_dir = %str(I:...ONS_Transf_20170523);
*location of code;
%let util_dir = &source_dir.%str(\dsp_utils);
%let datadir = %str(...KATER\DATA);
%let outdir = %str(...\KATER\Results);
%let paramf = &datadir.%str(\parameter_file\param.csv);
options mautosource mrecall sasautos=(sasautos "&source_dir" "&util_dir") nolabel;
%reset_saserror;
libname datain "&datadir";
options mstored sasmstore=datain;
libname outdir "&outdir.\output";
options mstored sasmstore=outdir;
%macro sdc_super_control_KAT;
%global liste_reg;
%let liste_reg=22 31;
%do k=1 %to %sysfunc(countw(&liste_reg.));
%let reg=%scan(&liste_reg.,&k.);
data hh_record;
set datain.hh_record_®.;
run;
data person_record;
set datain.person_record_®.;
run;
%let outdir_ = &outdir.\output_®.;
proc printto log = "&outdir_.Log.txt";
run;
/
%sdc_control;
*copy files to permanent library;
proc copy in=work out=outdir_;
select sdcresults_hh_:;
run;
proc printto;
run;
%end;
data outdir.params;
set diagnostics_params;
run;
%mend sdc_super_control_KAT;
%sdc_super_control_KAT;
I don't think you're showing us the full code. The issue above appears to be due to the ® macro variable not resolving to a value but there is nothing shown to indicate why that would happen. Also, the error messages are in the wrong order (hh_record_) should come first in the log.
In summary, it's because your reg variable is resolving to a missing value, or because it is not found (if not found, the log should say that though).
data classivar_1;
set classvar;
AnaClassVar=scan(scan(F2,1," "),2,".");
run;
proc sql;
select AnaClassVar into : MacClassVar separated by "#" from classivar_1 ;
select count(*) into: Count_classvar from classivar_1;
quit;
%put &MacClassVar.;
%put &Count_classvar.;
ods output variables=adsl_var;
proc contents data=ev.adsl;
run;
proc sql;
select variable into : AllVar separated by "#"
from adsl_var;
select count(*) into : Count_Allvar from adsl_var;
quit;
%put &Allvar.;
%put &Count_Allvar.;
**** set up Macro ClassAna to analyze the classified varialbes;
%macro ClassAna(datasets= );
%do i= 1 %to &Count_classvar.;
%do count=1 %to &Count_Allvar;
%if %sysfunc(find(%scan(&MacClassVar,&i,#),%scan(&AllVar,&count,#)))
%then %do;
%let Class_var&i.=%scan(&AllVar,&count,#);
%end;
%end;
%put &&Class_var&i..;
%end;
%Mend;
%ClassAna(datasets=sashelp.class)
When I submit the programme , the macro variable Class_var6 cannot be resolved.
But other macro variables can be resolved correctly.
The logs are in the picture.enter image description here
enter image description here
In %ClassAna you are conditionally creating the macro vars based on:
%if %sysfunc(find(%scan(&MacClassVar,&i,#),%scan(&AllVar,&count,#)))
%then %do;
That FIND is case sensitive by default. I think it will work if you make it case insensitive by adding the optional i parameter to FIND. Something like:
%if %sysfunc(find(%scan(&MacClassVar,&i,#),%scan(&AllVar,&count,#),i))
%then %do;
Or you could %upcase both variable lists and leave the FIND as is.
I have several .csv files in a folder that I would like to import into SAS. However, they are not always populated with data, so when I attempt to import an empty file into SAS, I get an error. I am wondering if there is some way for me to check whether or not an external file is empty, and if it is not, bring it into SAS. This is a code that I would like to automate and not have to manually check and account for blank files every time.
I came across this macro in SAS's knowledge base but am unsure of how to modify it so that it would import a .csv file, if I should be using it at all: http://support.sas.com/kb/25/072.html
I appreciate your help.
This is the macro in question from the link:
%macro test(outf);
%let filrf=myfile;
%if %sysfunc(fileexist(&outf)) %then %do;
%let rc=%sysfunc(filename(filrf,&outf));
%let fid=%sysfunc(fopen(&filrf));
%if &fid > 0 %then %do;
%let rc=%sysfunc(fread(&fid));
%let rc=%sysfunc(fget(&fid,mystring));
%if &rc = 0 %then %put &mystring;
%else %put file is empty;
%let rc=%sysfunc(fclose(&fid));
%end;
%let rc=%sysfunc(filename(filrf));
%end;
%else %put file does not exist;
%mend test;
%test(c:\test.txt)
What you'd want to do is change what the macro does in the case that the file is empty. In this case, the fget will return a 0 to the return code (%let rc = ... fget) if it is able to get a string, or it will fail and return a nonzero code.
So, just modify the %if / %else. Instead of putting something, you just do something like
%if &rc=0 %then %do;
%import_csv(&outf.);
%end;
%else %do;
%put File &outf. is empty.;
%end;
That assumes you have a macro that does your import. You could, of course, include the full PROC IMPORT code there instead.
This really makes a reasonable error checking wrapper to an import macro, in fact.
%macro import_csv(outf=,outds=);
%let filrf=myfile;
%if %sysfunc(fileexist(&outf)) %then %do;
%let rc=%sysfunc(filename(filrf,&outf));
%let fid=%sysfunc(fopen(&filrf));
%if &fid > 0 %then %do;
%let rc=%sysfunc(fread(&fid));
%let rc=%sysfunc(fget(&fid,mystring));
%let rc_close=%sysfunc(fclose(&fid));
%if &rc = 0 %then %do;
proc import file="&outf." out="&outds."
dbms=csv replace;
run;
%end;
%else %put File &outf. is empty and not imported.;
%end;
%let rc=%sysfunc(filename(filrf));
%end;
%else %put file does not exist;
%mend test;