JMPの複数ファイルインポートツールは、見つかったファイルのデータテーブルを作成できます。 添付のアドイン(JMP 16、Windowsのみ)のJSLは、そのデータテーブルを取得し、ファイルが使用するディスク領域のネストされたツリービューを作成します。 中速です。 Cドライブのルートから約30分で500Kのファイルをロードしました(退屈し、ニュースを見て、正確にはわかりません...)いくつかのファイルタイプのビューアがあります。以下に示すJSL。
ルートから開始しない方が高速です。
JSLは、ディレクトリのプロンプトから始まります。 ダブルクリックしてもディレクトリが選択されないため、これは常に使いにくいように見えます...ディレクトリが開きます。 ディレクトリを強調表示して、[OK]を選択します。 ディレクトリがMFIに渡され、ファイルリストが取得されます。 途中でキャンセルのチェックがいくつか行われます。
root = Pick Directory( "show directory sizes", "$Desktop/.." );
If( root == "", Throw( "canceled" ));
// use MFI to get a recursive file list with sizes and dates
mfi = Multiple File Import(
<<SET folder=""></SET>
からのいくつかの変更されたコードキャンセルボタン付きのプログレスバーこれにより、最後にプログレスバーウィンドウがリサイクルされます。
// Progressbar https://community.jmp.com/t5/Uncharted/Progress-Bar-with-Cancel-Button/ba-p/433560
progressBarWidth = 500;
cancel = 0; // clear the cancel flag
New Window( "Directory Tree", // this window gets reused below
windowbox = V List Box( //
t = Text Box( "", <<SETWRAP></SETWRAP>
そして、飛び込む時が来ました。 このコードはデータテーブルをパスし、ディスク上のフォルダツリーの形状を反映したツリーを構築します。 完了すると、すべてのデータが連想配列内のツリーに存在するため、データテーブルが閉じられます。 ツリーを接続するリンクは、実際には連想配列のキーです。
// look at every row in the data table and build a tree in an associative array. The keys in the
// array represent directories, NOT files. Files are held in a {list} at each directory level.
// file sizes are accumulated at each of the file's ancestor directory levels, so there is
// a grand total at the root.
init = {{/*immediate files and dirs*/}, 0/*aggregate file count*/, 0.0/*aggregate bytes*/}; // all dir nodes look like this; there is no date for dirs
directory = [=> ]; // associative array to hold the nodes
directory[root] = init; // the root node is handled separately
nBytes = 3;
nDate = nCount = 2;
For( irow = 1, irow <= nRowsDtFiles & !cancel, irow += 1,
levels = Words( dtFiles:FileName[irow], "/" ); // break out the directory levels for this row's file
path = root; // the root is not part of the file's path broken out in levels[] but is needed in the real path spec
size = dtFiles:FileSize[irow];
date = dtFiles:FileDate[irow];
// root handled separately...
directory[root][nCount] += 1; // item 2 in the init list is a count of files here AND below
directory[root][nBytes] += size; // item nBytes is the size of all files here AND below
For( ilevel = 1, ilevel < N Items( levels ), ilevel += 1,
parent = path;
path = path || levels[ilevel] || "\";
If( !Contains( directory, path ), // never seen this node before? create it!
directory[path] = init; // create with an empty list
// add this directory to the parent directory, at position 1 so dirs come first
// Important: the missing value in the 2-item list signals a directory, not date or size.
Insert Into( directory[parent][1], Eval List( {Eval List( {levels[iLevel], .} )} ), 1 ); // my parent dir points to me (I'm also a dir)
);
directory[path][nCount] += 1;// count files and subdirs
directory[path][nBytes] += size;
If( Mod( irow, 1000 ) == 0,
updateProgress( irow / nRowsDtFiles );
Wait( 0 );
);
);
// every row represents a file. This is inserted at the end so files come last, but that is no
// longer important since they are sorted together by descendingaggregate size
// Important: the 2nd item (date) in this list is not missing, so it is a file
If( Is Missing( date ),
Throw( "missing date?" )
);
Insert Into( directory[path][1], Eval List( {Eval List( {levels[iLevel], date, size} )} ) ); // also a 3-item list, not 2 for a dir
);
Close( dtFiles, nosave ); // done with the dt, the data is all loaded in the associative array
キャンセルを確認し、きれいなアイコンを作成し、プログレスバーの後半を設定します。 はい、独自のカスタムアイコンを作成するのはそれと同じくらい簡単です。 左から右への赤から灰色と赤の色合いの両方を変更することにより、アイコンはファイルサイズの膨大な範囲についてもう少し表現力豊かになります。
If( cancel, // test the cancel flag
Beep(); // audio flag
left << color( "dark red" ); // visual flag something is awry
right << color( "red" );
cancelButton << setbuttonname( "Close" ); // visual flag the button function is changed
cancelButton << setscript( (cancelButton << closewindow) ); // and what to do if the button is pressed
Stop();
, //
updateProgress( 1.0 ); // people like to see the bar go to 100%
);
// make icons
redcolor = {0.627450980392157, 0.0352941176470588, 0.133333333333333};
graycolor = {0.831372549019608, 0.831372549019608, 0.831372549019608};
ncons = 64;// width, height, and n. the actual displayed icon may be smaller, the shades will help
For( i = 0, i <= ncons, i += 1,
// the width of the red and the shade of the red are both diminishing because
// there is a huge range to cover and this helps express small vs large better
H List Box(
Spacer Box( size( i, ncons ), color( RGB Color( redcolor * (i / ncons) + graycolor * (1 - i / ncons) ) ) ), // left side
Spacer Box( size( ncons - i, ncons ), color( RGB Color( graycolor ) ) ) // right side
) << savepicture( "$temp/deletemeIcon" || Char( i ) || ".png" )
);
biggestsize = Log( directory[root][nBytes] + 1 );// biggest in this tree is dark red square; near 0 is all light gray
icon = Function( {size}, // get the right icon for this file size
size = Floor( ncons * Log( size + 1 ) / biggestsize );
"$temp/deletemeIcon" || Char( size ) || ".png";
);
// update progressbar for 2nd phase this way...
updateProgress2 = Function( {fractionComplete},
leftsize = Round( .5 * progressBarWidth + progressBarWidth * fractionComplete * .5 ); // second half of progress bar
rightsize = progressBarWidth - leftsize;
left << width( leftsize );
right << width( rightsize );
t << settext( Eval Insert( "finishing up display constuction ^filesDone^ / ^nRowsDtFiles^" ) );
t << updatewindow; // this works without the wait
);
探索機能は再帰的です。連想配列内のツリーを探索し、ソートされたツリーノードコントロールを構築します。
// recursive function to explore the tree loaded in the associative array and build the treenode structure
explore = Function( {path, attachpoint},
{treeNode, list, childpath, nfiles, bytes, appendTnode, appendSizes, m, newbutton},
list = directory[path][1]; // all the files and subdirs of this node
// keep two parallel lists of TreeNodes and the size of the object represented
// later, use rank() to sort them so the big objects are at the top of the display
appendTnode = {};
appendSizes = {};
For Each( {namedata}, list, // subdir or file? subdir will recurse, file is a leaf.
If( Is Missing( namedata[nDate] ), // then this is a dir {name, . }
If( N Items( namedata ) != 2,
Throw( "dir? " || Char( namedata ) ) // unexpected bug
);
childpath = path || namedata[1] || "\";
nfiles = directory[childpath][nCount];
bytes = directory[childpath][nBytes];
treeNode = Tree Node(
Eval Insert(
"\[^Format(bytes, "Fixed Dec", Use thousands separator( 1 ), 30, 0 )^ bytes in directory with ^nfiles^ items ^namedata[1]^]\"
)
);
treeNode << seticon( icon( bytes ) );
treeNode << setdata( childpath );
explore( childpath, treeNode ); // recursion! build the subtree
Insert Into( appendTnode, treeNode );
Insert Into( appendSizes, bytes );
, // else a file belonging to path { name, bytes, date}
treeNode = Tree Node(
Eval Insert(
"\[^Format(namedata[nBytes], "Fixed Dec", Use thousands separator( 1 ), 30, 0 )^ bytes updated ^round((today()-namedata[nDate])/inweeks(1))^ weeks ago ^namedata[1]^]\"
)
);
treeNode << seticon( icon( namedata[nBytes] ) );
childpath = path || namedata[1];
treeNode << setdata( childpath );
Insert Into( appendTnode, treeNode );
Insert Into( appendSizes, namedata[nBytes] );
filesDone += 1;
If( Mod( filesDone, 100 ) == 0,
Try( updateProgress2( filesDone / nRowsDtFiles ) );
Wait( 0 );
If( cancel,
Beep(); // audio flag
left << color( "dark red" ); // visual flag something is awry
right << color( "red" );
cancelButton << setbuttonname( "Close" ); // visual flag the button function is changed
cancelButton << setscript( (cancelButton << closewindow) ); // and what to do if the button is pressed
Throw( "canceled" );
);
);
)
);
m = Rank( appendsizes );
For( j = N Items( m ), j >= 1, j--, // biggest first, rank from small to large
i = m[j];
attachpoint << append( appendTnode[i] );
);
);
TreeClickHandlerは、いくつかのファイルタイプの単純なビューアを開きます。
// click handler for tree nodes
treeClickHandler = Function( {thistree, thisnode}, // a few viewers for common file types
{extension, data, tablename, nodedata, nodelabel},
nodelabel = thisnode << getlabel;
nodedata = thisnode << getdata;
// show(nodelabel,nodedata);
line1 << settext( nodelabel );
line2 << setbuttonname( nodedata );
// show(line2<<GETBUTTONNAME>1MB, too big for this viewer, click link above to open it" ) );//
);//
, /*else if*/
Ends With( extension, "\" ), //
view << append( Text Box( "This is a directory. Click the link above to open it." ) );//
, // else
view << append( Text Box( "Not sure what this is, don't click the link unless you want JMP to open() it." ) );//
);
);
</GETBUTTONNAME>
最後に、ルートノードを作成し、それをexplore()に渡し、ツリーボックスを含むウィンドウを作成してツリーノードコントロールを表示します。 ファイルを開くボタンがあります。慎重に押す必要があります。 実行可能なファイル拡張子の短いリストがありますが(表示されていません)、問題を回避するために、包括的ではありません...
rootTreeNode = Tree Node( Eval Insert( "\[^Format(directory[root][nBytes], "Fixed Dec", Use thousands separator( 1 ), 30, 0 )^ ^root^]\" ) );
rootTreeNode << seticon( icon( directory[root][nBytes] ) );
explore( root, rootTreeNode );
windowbox = windowbox << parent;
(windowbox << child) << delete;
windowbox << append(
H Splitter Box(
size( 1000, 600 ),
treebox = Tree Box( rootTreeNode ),
vlistbox = V List Box(
line1 = Text Box(), // also updated by treeClickHandler
line2 = Button Box( "", // gets link-style, below. Visible name updated by treeClickHandler script.
setfunction( // when the button clicks, use its current visible name to open() the file.
Function( {this},
name = this << getbuttonname;// the underlined button name *is* the file name
extension = Uppercase( Regex( name, ".*?([^\.]*)$", "\1" ) );
If( !Contains( executable, extension ), // seems a bad idea
Open( name, Add to Recent Files( 0 ) )
,
Beep()
);
)
)
),
scrollbox = Scroll Box( view = Border Box() )
)
)
);
windowbox << Set Window Title( "Directory Tree " || root );
line2 << UnderlineStyle( 1 );
line1 << Set Stretch( "fill", "off" );
line2 << Set Stretch( "fill", "off" );
scrollbox << Set Stretch( "off", "off" );
treebox << Set Auto Stretching( 1, 1 ) << Set Max Size( 10000, 10000 ) << User Resizable( {0, 0} );
scrollbox << Set Auto Stretching( 1, 1 ) << Set Max Size( 10000, 10000 ) << User Resizable( {0, 0} );
treebox << Set Node Select Script( treeClickHandler );
treebox << expand( rootTreeNode );
絵
テーブル
ジャーナル
アドインをインストールすると、view-> addinsを使用してJSLを確認できます。 ダウンロードして、拡張子を.zipに変更することもできます。
(このJSLの最初のパスでは、ツリーノードよりもはるかに多くのベルとホイッスルを可能にするアウトラインノードを使用しました。 ただし、アウトラインノードは100K以上のネストされたノードの表示には適していません。ツリーノードはそのジョブ用に設計されています。 残りのアウトライン参照を見つけた場合(私はそれらをクリーンアップしたと思います...)、それが起こったのです。)