制作一个简单的目录可视化工具 (Dir-chart)

Mr_MAO 1天前 148

import godking.comboboxEx;
import fonts.fontAwesome;
import win.ui;
/*DSG{{*/
var winform = win.form(text="Dir-Chart   (By: Mr_MAO)";right=759;bottom=471;clipch=0;edge=1)
winform.add(
comboboxEx={cls="comboboxEx";left=16;top=16;right=256;bottom=48;bgcolor=0x008000;clipch=1;dl=1;dt=1;z=1};
custom1={cls="custom";left=264;top=16;right=744;bottom=232;ah=1;border=1;clipch=1;dr=1;dt=1;edge=1;z=7};
custom2={cls="custom";left=264;top=240;right=744;bottom=456;ah=1;bgcolor=0xFFFFFF;border=1;clipch=1;db=1;dl=1;dr=1;edge=1;z=3};
plus2={cls="plus";left=744;top=456;right=760;bottom=472;bgcolor=0xFFFFFF;edge=1;iconColor=0xFFC0A0;iconStyle={font=LOGFONT(h=-24;name='FontAwesome')};z=6};
splitterH={cls="splitter";left=264;top=232;right=744;bottom=240;dl=1;dr=1;horz=1;z=4};
splitterV={cls="splitter";left=256;top=16;right=264;bottom=456;db=1;dl=1;dt=1;z=5};
treeview={cls="treeview";left=16;top=59;right=256;bottom=456;asel=false;bgcolor=0xFFFFFF;clipch=1;db=1;dl=1;dt=1;edge=1;infoTip=1;z=2}
)
/*}}*/

import sys.volume;
import fsys;
import fsys.info;
import JSON;

//=========splitter======================
winform.splitterH.split(winform.custom1,winform.custom2);
winform.splitterH.ltMin = 150;   
winform.splitterH.rbMin = 150;   
winform.splitterV.split({winform.comboboxEx;winform.treeview},{winform.custom1;winform.splitterH;winform.custom2});
winform.splitterV.ltMin = 100;   
winform.splitterV.rbMin = 100;   

//=========comboboxEx 下拉磁盘列表=================
import win.imageList; 
var imglst = win.imageList(45, 32);

var comboTexts = {}
var comboValues = {}
var localDrives = sys.volume.getLogicalDrives();
for (i=1; #localDrives; 1) {
    var info = sys.volume.getInfo(localDrives[i]);
    var driveName = info.drive;
    table.push(comboTexts, driveName ++ " (" ++ ((#info.label)?info.label:"本地磁盘") ++ ")") 
    table.push(comboValues, driveName) 
    
    var sfi = fsys.info.get(driveName, 0x100/*_SHGFI_ICON*/ |  0/*_SHGFI_LARGEICON*/);
    var bmpIcon = gdip.bitmap(sfi.hIcon,1);
    var bmpNew= gdip.bitmap(45,32);
    var g = bmpNew.getGraphics();
    g.drawImageRect(bmpIcon,12,0,30,30);
    imglst.addBitmap( bmpNew.copyHandle())
}
winform.comboboxEx.setImageList(imglst);
winform.comboboxEx.setFont(h=-12;name="Microsoft YaHei UI");
winform.comboboxEx.setItems(comboTexts,,comboValues);
winform.comboboxEx.selIndex = 1;
winform.comboboxEx.readonly = true; 

//=========treeview 目录列表 explorer============
import win.ui.explorer;
var explorer = win.ui.explorer( winform.treeview );
explorer.dirFirst = false;
explorer.loadFile("c:\", "") //仅显示目录视图

//=========custom====================
import web.form;
wbChart = web.form(winform.custom1)
wbList  = web.form(winform.custom2)

wbChart.noScriptErr = true;
wbChart.showMenu = function(x,y,id,ele){
    return false; //屏蔽右键菜单
}

//=============线程调用函数=========================
getchildFoldersInfo = function(parentFolder){
    import dotNet; 
    import fsys;
    
    // 编译C#代码
    var compiler = dotNet.createCompiler("C#");
    compiler.Source = /**
        using System;
        using System.IO;
        using System.Threading;
        using System.Threading.Tasks;
        namespace CSharpLibrary  
        { 
            /*利用C#快速获取文件夹大小*/
            public static class FolderSizeCalculator {
                public static long CalculateDirectorySize(string rootPath) {
                    /* 长路径支持 */ 
                    if (rootPath.Length >= 260 && !rootPath.StartsWith(@"\\?\")) {
                        if (rootPath.StartsWith(@"\\")) {
                            rootPath = @"\\?\UNC\" + rootPath.Substring(2);
                        }
                        rootPath = @"\\?\" + rootPath;
                    }
            
                    long totalSize = 0;
                    var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
                    
                    try {
                        Parallel.ForEach(Directory.EnumerateFiles(rootPath), options, file => {
                            try {
                                Interlocked.Add(ref totalSize, new FileInfo(file).Length);
                            } 
                            catch { /* 忽略权限错误等 */ }
                        });
                    } 
                    catch (UnauthorizedAccessException) { return totalSize; }
                    catch (DirectoryNotFoundException) { return totalSize; }
          
                    var subDirs = Directory.EnumerateDirectories(rootPath);
                    Parallel.ForEach(subDirs, subDir => {
                        Interlocked.Add(ref totalSize, CalculateDirectorySize(subDir));
                    }); 
            
                    return totalSize;
                }
            }
        }
        **/;
    compiler.import("CSharpLibrary"); 
    
    var arr = {}
    fsys.enum( parentFolder, "*.*",
        function(dir,filename,fullpath,findData){ 
            if(filename){ 
                var size = tonumber( math.size64(findData.nFileSizeLow,findData.nFileSizeHigh) );
                table.push(arr, {ftype=1; fname="📄 " ++filename; fsize=size})
            }
            else{
                var size = CSharpLibrary.FolderSizeCalculator.CalculateDirectorySize(fullpath);
                table.push(arr, {ftype=2; fname="📂 " ++dir; fsize=size})
            }
        }, false
    );
    
    return arr;
}

//============合并太小的文件或文件夹的函数=========================
var combineSmallItems = function(list){
    if(#list>20){ //(目录数+文件数)<=20不处理
        var totalsize = 0;
        var folders ={}
        var files ={}
        for(i=1;#list;1){
            totalsize += list[i].fsize;
            if(list[i].ftype==1){
                table.push(files, list[i])
            }else{
                table.push(folders, list[i])
            }
        }
        if(totalsize==0) return list;
        
        //合并小目录
        if(#folders>8 ) {
            var index = 0
            table.every(folders,function(v,k){
                index = k  //获取临界点
                return v.fsize/totalsize > 0.03;   //小于文件夹总尺寸3%的小目录合并 
            }) 
            if(index>2 && index<#folders-2){
                //删掉原数组中的小目录
                var tempFD = table.splice(folders,index,#folders-index+1); 
                var tempSum = 0
                for i,v in table.eachIndex(tempFD){
                    tempSum += v.fsize  //合并小文件的大小为一个值
                }
                table.push(folders,{ftype=2; fname="📂 其它目录"; fsize=tempSum})
            }
        }
        
        //合并小文件
        if(#files>8 ) {
            var index = 0
            table.every(files,function(v,k){
                index = k
                return v.fsize/totalsize > 0.03; 
            })
            if(index>2 && index<#files-2){
                //删掉原数组中的小文件
                var tempFL = table.splice(files,index,#files-index+1); 
                var tempSum = 0
                for i,v in table.eachIndex(tempFL){
                    tempSum += v.fsize
                }
                table.push(files,{ftype=1; fname="📄 其它文件"; fsize=tempSum})
            }
        }
        return table.concat(folders, files)
    }
    return list; 
}
//============================================

wbChart.external = {
    getfolderDatas = function(path){
        if( fsys.isDir( path ) ) { //如果点击的是文件夹
            if( #path<=3 ) {//根目录
                var deviceData = sys.volume.getSpaceSize(path); //获取磁盘数据
                var totalB = deviceData.totalSize;
                var freeB = deviceData.freeSize;
                var usedB = totalB-freeB;
                
                var newdatas = {{name='已使用空间';value=tonumber(usedB)};{name='未使用空间';value=tonumber(freeB)}}
                return JSON.stringify( newdatas );
                
            }else{ //子目录
                //开新线程调用C#函数
                var list = thread.invokeAndWait(getchildFoldersInfo, path)
                
                //处理返回的数据表
                if(list){
                    //按文件夹\文件大小排序
                    table.sort(list,function(next){
                        if(owner.ftype > next.ftype){ //降序
                            return true;
                        }elseif(owner.ftype==next.ftype){
                            return owner.fsize > next.fsize;
                        }
                        return false;
                    }); 
                    //合并小目录和小文件
                    list = combineSmallItems(list) 
                   }
                //返回Echart可以调用的data
                var newdatas = table.map(list,function(v,k,result){
                    table.push(result,{name=v.fname; value=tonumber(v.fsize) })
                })
                return JSON.stringify( newdatas );
            }
        }
    }
}

wbChart.html = /**
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="https://aar.chengxu.online/upload/attach/202509/62_NTTGT4KBFE9WJ5D._js"></script>
  <style>
    body { overflow-y: hidden !important; }
    #chart-container {
        display: flex; justify-content: center;
        width: 100%; height: 100vh;
    }
  </style>
</head>
<body>
<div id="chart-container">
  <div id="mychart" style="width:100%; height:100%;"></div>
</div>
<script>
    const chart = echarts.init(document.getElementById('mychart'));
    const option = {
         tooltip: {
            trigger: 'item',
            formatter: function(params) {
                let name = params.name;
                let value = params.value;
                return params.marker + name + ": <b>" +  window.formatFileSize(value) + "</b>";
            }
        },
        series: [{
            type: 'pie',
            radius: ['30%', '65%'],
            center: ['50%', '50%'],
            data: [],
            label: { 
                show: true,
                formatter: '{b}: {d}%'
            }, 
            emphasis: {
                itemStyle: {
                    shadowBlur: 10,
                    shadowOffsetX: 0,
                    shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
            }
        }]
    };

    chart.setOption(option);
    
    // 更新chart中的数据
    window.updateChartDatas = function(path) {
        const option = chart.getOption();
        const newDatas = external.getfolderDatas(path);
        option.series[0].data = JSON.parse(newDatas);  //JSON转数组
        chart.setOption(option);
    };
    
    window.addEventListener('resize', chart.resize);
    
    window.formatFileSize = function(fileSize) {
        if (fileSize < 1024) {
            return fileSize + ' Bytes';
        }else if (fileSize < 1024 * 1024) {
            return (fileSize / 1024).toFixed(2) + ' KB';
        }else if (fileSize < 1024 * 1024 * 1024) {
            return (fileSize / (1024 * 1024)).toFixed(2) + ' MB';
        }else {
            return (fileSize / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
        }
    }    
</script>
</body>
</html>
**/
wbChart.wait(); 

//显示图表
wbChart.xcall("window.updateChartDatas", "c:"); 

winform.custom1.adjust = function( cx,cy,wParam ) {     
    winform.plus2.setPos(owner.getPos())      
};

//=======comobox 磁盘列表事件=======
winform.comboboxEx.onOk = function(){ 
    if( owner.text !==  owner.selText) {
        var path = winform.comboboxEx.getItem(owner.selIndex).value;
        explorer.loadFile(path, "")
        wbList.go(path++"\"); 
        
        winform.plus2.hide = true;
        wbChart.show(true);
        //更新图表
        wbChart.xcall("window.updateChartDatas", path )
    }
}

//=======treeview 目录列表事件=======
explorer.onClick = function(filePath,hItem ){
    if( fsys.isDir( filePath ) ) {
        wbList.go( filePath );  
    }
}

//=======webform 文件列表事件=======
wbList.BeforeNavigate2 = function( pDisp, url, flags, targetFrame, postData, headers, cancel ) {
    if( fsys.isDir( url ) ) {
        winform.plus2.setPos(winform.custom1.getPos())
        winform.plus2.text = "";
        winform.plus2.hide = false;
        winform.plus2.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']
        wbChart.show(false)
        
        var files,dirs= fsys.list(url)    
        if(#files>0 || #dirs>0){//先判断是不是空文件夹
            wbChart.xcall("window.updateChartDatas", url );
            
            winform.plus2.disabledText = null;
            winform.plus2.hide = true; 
            wbChart.show(true)
        }else{
            winform.plus2.disabledText = null;
            winform.plus2.text = "空文件夹";
        }
    }
}

wbList.NavigateComplete2 = function(pDisp, url) {
    var shellView = wbList.document;
    if (shellView) {
        shellView.CurrentViewMode = 4;//始终显示为[详细列表]样式
    }
}

wbList.DocumentComplete = function(pDisp,url) { 
    if( fsys.isDir( url ) ) {
        //回选treeview相应的节点
        var hItem = winform.treeview.findPath(,string.right(url,-4));
        winform.treeview.expand(hItem);
        winform.treeview.selDropHiLite(hItem)
    }
}

winform.plus2.hide = true;
wbList.go("c:\");

winform.disableDragFullWindow = true;
winform.show();
win.loopMessage();
上传的附件:
最新回复 (1)
  • 光庆 1天前
    0 2

    牛X,厉害!

返回