
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();