2017-06-29 13 views
0

Linuxマシンの1つのフォルダに膨大な数の.csvファイル(数ギガバイト)の最初と最後のレコードを読みたい。それらがhave1.csv, have2.csv, ...と呼ばれているとします。SAS - 複数のcsvファイルの最初と最後の観察を読む

私は次のコードを試しました。私は最初の行だけを与えてくれました。しかし、最後の行ではありません。

%let datapath = ~/somefolder/;  
data want; 

length finame $300.; 
/*Reference all CSV files in input data folder*/ 
infile "&datapath.have*.csv" delimiter="," 
     MISSOVER DSD lrecl=32767 firstobs=2 
     eov=eov eof=eof filename=finame end=done; 

/*Define input format of variables*/ 
informat Var1 COMMA. Var2 COMMA. Var3 COMMA.; 
/*Loop over files*/ 
do while(not done); 

    /*Set trailing @ to hold the input open for the next input statement 
     this is because we have several files */ 
    input @; 

    /*If first line in file is encountered eov is set to 1, 
     however, we have firstobs=2, hence all lines would be skipped. 
     So we need to reset EOV to 0.*/ 
    if eov then 
    do; 
     /*Additional empty input statement 
     handles missing value at first loop*/ 
     input; 
     eov = 2; 
    end; 
    /*First observation*/ 
    if eov=2 then do; 
     input Var1--Var3; 
     fname=finame; 
     output; 
     eov = 0; 
    end; 

     /*Last observation*/ 
     if 0 then do; 
      eof:  input Var1--Var3; 
        fname=finame; 
        output; 
     end; 
     input; 

end; 
stop; 

run; 

ご協力いただきありがとうございます。 infile、end、eov、eof、input @のコンセプトや相互作用を誤解している場合は教えてください!私の間違いがある場合、私はこれが私のために動作するようです...

+1

ヘッダー行もスキップしますか? FIRSTOBS =オプションに関するコメントは何ですか? – Tom

+0

はい、以前に書き返していないのは申し訳ありません。 –

答えて

1

(私たちはデータステップ自体でループしているので、追加する必要が保持)新しいファイルが開始されたときにフラグを立てる変数を作成します。 EOVフラグを手動でリセットする必要があることに注意してください。

新しいファイルが開始されたかどうかをテストできるように、値を読み取る前に行を読み取り、保持します。これにより、前のファイルから最後の行を出力することができます。また、前のファイルの最後の行からの値が利用できるように入力変数を取り消す必要があります。

また、最後のファイルの最後の行を出力するには、END =オプションを使用する必要があります。

例:

data want ; 
    retain filename str; 
    length fname filename $200 ; 
    infile '/dir1/file*' filename=fname eov=eov end=eof truncover ; 
    input @; 
    if eov then output; 
    filename=fname ; 
    input str $30. ; 
    if _n_=1 or eov or eof then output; 
    eov=0; 
run; 

出力例:

Obs filename  str 
1  /dir1/file1 Line1 
2  /dir1/file1 Line3 
3  /dir1/file2 Line1 
4  /dir1/file2 line4 
5  /dir1/file3 Line1 
6  /dir1/file3 Line3 

あなたは右input @;文の後にこの文を追加し、各ファイル(ヘッダ行)の最初の行をスキップしたい場合。

if _n_=1 or eov then input; 

注あなたはそれが可能であれば、あなたの入力ファイルはすべて、少なくとも2本のデータ線(ヘッダ行をカウント3行)がないことのロジックを調整する必要があります。

+1

これは素晴らしい答えです。CSVファイルに変数名を含むヘッダー行が含まれていない場合、残念ながら、私の持っている...申し訳ありませんが十分に明確にしていない。 しかし、各ファイルの最初の観測をスキップして、PDVが最初の行のヘッダー情報から入力を受け取らないようにする方法はありますか?この場合、私は残念なことにあなたの解決策が実際に働くと思います... –

+0

end =オプションは最後のファイルの最後の行だけをキャッチするようです。とにかくループが必要な間、あなたは何も証明しませんでした。 – vasja

+0

ヘッダー行をスキップするのは難しくありません。スキップする必要があるときは、EOVフラグを使用して確認します。 – Tom

1

を知らない、それを試してください:トムは、以下の説明として

data want; 

length finame $300.; 
/*Reference all CSV files in input data folder*/ 
infile "E:\temp\test\have*.txt" delimiter="," 
     MISSOVER DSD lrecl=32767 
     eov=eov filename=finame end=done; 

     /* Note: firstobs option seems to work on first file only */ 

/*Define input format of variables*/ 
informat Var1 COMMA. Var2 COMMA. Var3 COMMA.; 

input; /* skip header in first file */ 

input Var1--Var3; /* read first real record in first file */ 
fname=finame; 
output; 

/* Loop over files*/ 
do while(not done); 

    input @;/* try input do determine eov condition */ 

    if eov then do;/* new file detected - we're on header record, but variables contain values from previous record - see "read values" */ 
     output; /* variables contain values from previous record - output those values */ 
     input; /* skip header */ 
     eov = 0; 
     input Var1--Var3; /* read first real observation */ 
     fname=finame; 
     output; /* first line of new file */ 
    end; 

    input Var1--Var3; /* read values - it might be last record */ 
end; 
output; /* output last record of last file */ 
run; 

は実際には、whileループ(危険な事のための必要はありません - ))。 私は今、コードを変更した:あなたはあなたにEOV =オプションを使用することができINFILE文でワイルドカードを使用したい場合は

data want; 

length finame $300.; 
/*Reference all CSV files in input data folder*/ 
infile "E:\temp\test\have*.txt" delimiter="," 
     MISSOVER DSD lrecl=32767 
     eov=eov filename=finame end=done; 

informat Var1 COMMA. Var2 COMMA. Var3 COMMA.; 
retain Var1 Var2 Var3 fname; 
if _N_ = 1 then do; /* first file */ 
    input; /* skip header in first file */ 
    input Var1--Var3; /* read first real record in first file */ 
    fname=finame; 
    output; 
end; 

input @; /* try input do determine eov condition */ 

if eov then do; /* new file detected - we've moved past header record, but variables contain values from previous record - see "read values" */ 
    output; /* variables contain values from previous record - output those values */ 
    input; /* skip header */ 
    eov = 0; 
    input Var1--Var3; /* read first real observation */ 
    fname=finame; 
    output; /* first line of new file */ 
end; 
else input Var1--Var3; 
if done then output; 
run; 
+0

これは素晴らしい作品です。それぞれの行を入力するとトリックが、最後の出力のみ、私に起こっていない...うまくいった!ありがとう! :D –

+0

申し訳ありません。私は2つの答えを与えることはできません。トムは正しい。彼のコードは少しはっきりしています。しかし、あなたもうまくいきます。私は引き裂かれています...皆さんのお手伝いをありがとうございます! :D –

1

ファイルのリストがある場合は、コードが明確になります。たとえば、PIPEエンジンを使用できる場合は、ls(またはDir)コマンドを使用してファイル名を取得できます。次に、FILEVAR =オプションを使用して個々のファイルを動的に読み込みます。

data want ; 
    infile 'ls ~/test/dir1/file*' pipe truncover ; 
    input fname $200.; 
    filename=fname; 
    infile csv filevar=fname dsd truncover firstobs=2 end=eof ; 
    do _n_=1 by 1 while (not eof); 
    input str :$30. ; 
    if _N_=1 or eof then output; 
    end; 
run; 

またはあなたのファイルが大きい場合は、SASは、ファイル全体を読み込む必要がありする必要なしに、各ファイルの始まりと終わりを見つけることheadtailコマンドを使用するPIPEを使用しての利点を取ることができます。実際にパフォーマンスを改善したかどうかをテストする必要があるでしょう。

data want ; 
    infile 'ls ~/test/dir1/file*' pipe truncover ; 
    input filename $200.; 
    length cmd1 cmd2 $200 ; 
    cmd1='head -2 '||filename ; 
    infile top pipe filevar=cmd1 dsd truncover firstobs=2 end=eof1 ; 
    if (not eof1) then do; 
    input str :$30. ; 
    output; 
    end; 
    cmd2='tail -1 '||filename ; 
    infile bottom pipe filevar=cmd2 dsd truncover firstobs=1 end=eof2; 
    if (not eof2) then do; 
    input str :$30. ; 
    output; 
    end; 
run; 
+0

ヘッドとテールのソリューションはそれほど高速ではありません。遅い方。 findコマンドで調整する必要がありました '' cd〜/ thepath; find。type -f -name "" * .csv "" -print "'リストを生成するには... –

関連する問題