Jump to content
Macro Express Forums

Challenge: a macro to report the size of a folder


Recommended Posts

One of my clients is a tech-savvy blind guy. He accesses his computer via JAWS, a screen reader application. A screen reader is software, driven by pressing keys, that reads screen content out loud.

 

He uses the Windows File Explorer to manage his folders and files. He has set File Explorer to always be in "Details" view. When configured this way, he can easily read the names of all documents and folders contained in a folder, the last date a file or folder was modified, and the file type:

 

image.png.1649ea3a0e9f5159158a8a1fc685d143.png

 

Although he needs to keep track of the sizes of files and folders, File Explorer only shows the size of files. It does not show the size of folders. (See red box, above.)

 

The reason: performance. If folder sizes were displayed, every time a user navigates through a folder structure, Windows would need to scan subfolders and files, record the sizes of every object, and sum them. This would require significant processor overhead.

 

The way to obtain the size of a folder is to open its "Properties" window. When Properties opens, Windows starts scanning the folder. On my computer, it takes nine or ten seconds to calculate the size of a folder that contains many subfolders and files.

 

The Properties window is challenging to navigate with a screen reader. Why? The short explanation is that it's not possible to reach the "Size" field by pressing the Tab key. (It can be done, but requires more work.)

 

The challenge: Use Macro Express to write a hotkey macro for the main File Explorer User Interface that reports, in a message box, the size of the selected folder:

image.png.93daa9dfd528ccf179ab4ee63c49dd89.png

Link to comment
Share on other sites

Here's a different technique, which I have used extensively in the past to develop lists of files with various attributes:

 

The macro can issue a DOS-style command directing its output to a file.  For this problem, the command would be DIR DIRPATH  /S  >C:\Temp\filelist.txt, which lists all files in the specified folder and in all subfolders.  The macro can then read and process filelist.txt, whose next-to-last line contains the cumulative number and size of the files.  It is fairly simple to find the line and extract the totals. 

Link to comment
Share on other sites

1 hour ago, acantor said:

That would be a far more elegant solution than mine... But will it work?

Yes it will work.  I don't know that it is more elegant than your solution, but it is simple and straightforward, and has lots of possibilities beyond simply reporting folder size.  I used the technique to automate processing on a server which contained extremely large individual backup files.  The DIR commands were in .bat files that were scheduled by Windows.  Then ME would schedule subsequent scripts to process the DIR output and generate additional .bat commands to compress the backup files and send the compressed files off to long-term tape storage.  A few simple batch files and ME scripts replaced an expensive commercial system that didn't work worth sh*t anyway.  😋

Link to comment
Share on other sites

I used rberq's method, but with the command slightly changed to show only the summary. It found me the size in bytes of the folder specified:


dir "C:\Users\terry\Dropbox\Dropbox (Sundry)" | find "(s)"

 

But the familiar right click > Properties method was very fast too, and displays it in MB too.

 

 

 

CommandForFolderSize.jpg

Link to comment
Share on other sites

5 hours ago, terrypin said:

dir "C:\Users\terry\Dropbox\Dropbox (Sundry)" | find "(s)"

Very clever.  And simpler than mine.  I never thought of piping the output to another command, and to be honest I wasn't even familiar with "find".  Now if we direct output of "find" to a text file, ME can very quickly read it and display the message box called for by the original challenge. 

 

Microsoft over the years has quietly made the traditional "DOS" commands much more powerful and elaborate.  And usually, these days, they actually work, which is a change from the good old days.  😉

 

pipe.JPG.3e01dae866f8ae937d5f47ce1f9d7b08.JPG

Link to comment
Share on other sites

Quote

I never thought of piping the output to another command, and to be honest I wasn't even familiar with "find". 

 

Me neither 🙂

But I was curious as to whether there was a way to deliver the size and little else. I tried the multitude of never used Nirsoft stuff I have, then hunted around online and came across that.

 

I also rashly installed JAWS (30-day trial) but gave up trying to get it to talk, and promptly removed it!

Link to comment
Share on other sites

Quote

I also rashly installed JAWS (30-day trial) but gave up trying to get it to talk, and promptly removed it!

 

JAWS is not an easy program to learn, never mind master. And to begin to climb that steep learning curve, there is a prerequisite: the ability to perform everyday tasks using only the keyboard. In other words, drop the mouse behind your desk, and don't touch it!

 

When I was learning JAWS, I found it helpful to close my eyes – a lot. For those of us who have habituated to performing computer tasks visually, I found that watching the screen interfered with learning the skills necessary to control a computer auditorily.

Link to comment
Share on other sites

I'm not sure rberq's and terry's clever solution is giving accuracy results! I checked the folder size for c:\windows in two ways:

 

1. From the command line: dir c:\windows | find "(s)"

 

2. From the Properties screen for c:\Windows

 

Here are the results:

 

image.png.21275d160d1a39b7e1c262e3a0df7ca0.png

 

Any ideas about which value is correct? Perhaps both are wrong??

Link to comment
Share on other sites

We could discuss approaches using command prompts, batch files, PowerShell scripts, etc for a long time! But I think the simplest method would be to use Properties, as in my example below.

 

// Open context menu for selected folder
Text Type (Simulate Keystrokes): <SHIFT><F10>
Delay: 0.1 seconds
// Open Properties
Text Type (Simulate Keystrokes): <ARROW UP><ENTER>
Wait for Window Title: Properties
// Select Name
Text Type (Simulate Keystrokes): <SHIFT><TAB>
Delay: 0.1 seconds
// Move mouse to right of Size line
Mouse Move: 320, 184 Relative to Current Window
Mouse Left Click
// Select text on Size line
Text Type (Simulate Keystrokes): <SHIFT><HOME>
Delay: 0.1 seconds
// Capture size as a text variable and display it
Clipboard Copy
Variable Set String %tFolderSize% from the clipboard contents
Text Box Display: Size of Folder

<COMMENT Value="Open context menu for selected folder"/>
<TEXT TYPE Action="0" Text="<SHIFT><F10>"/>
<DELAY Flags="\x01" Time="0.1"/>
<COMMENT Value="Open Properties"/>
<TEXT TYPE Action="0" Text="<ARROW UP><ENTER>"/>
<WAIT FOR WINDOW TITLE Title="Properties" Partial="TRUE" Wildcards="FALSE" Indefinite="TRUE" Hours="0" Minutes="0" Seconds="0"/>
<COMMENT Value="Select Name"/>
<TEXT TYPE Action="0" Text="<SHIFT><TAB>"/>
<DELAY Flags="\x01" Time="0.1"/>
<COMMENT Value="Move mouse to right of Size line"/>
<MOUSE MOVE Option="\x02" X="320" Y="184" _PROMPT="0x000A"/>
<MOUSE LEFT CLICK/>
<COMMENT Value="Select text on Size line"/>
<TEXT TYPE Action="0" Text="<SHIFT><HOME>"/>
<DELAY Flags="\x01" Time="0.1"/>
<COMMENT Value="Capture size as a text variable and display it"/>
<CLIPBOARD COPY/>
<VARIABLE SET STRING Option="\x02" Destination="%tFolderSize%" NoEmbeddedVars="FALSE"/>
<TEXT BOX DISPLAY Title="Size of Folder" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang2057{\\fonttbl{\\f0\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\qc\\b\\f0\\fs40 \r\n\\par %tFolderSize%\\b0\\fs20 \r\n\\par }\r\n" Left="749" Top="620" Width="575" Height="200" Monitor="0" OnTop="TRUE" Keep_Focus="TRUE" Mode="\x00" Delay="0"/>
  
  

 

If that proves unbearably slow for very large folders (like C:\Windows) then let's return to those other more advanced methods. As apparent from my last post, these days when I need that sort of info I resort to intelligent googling. Life's too short!

 

--------------------

 

I'm not entirely clear about your client's needs? Will the macro always start in a folder, with one of its subfolders selected, as you imply? Or could the target be the current folder? How will the client select the target? What limitations are there on what JAWS can read out? For example, would the screenshot below offer another approach?

 

And will the client be happy to use the macro successively, rather than a columnar display of folders, such as the TreeSize suggestion I made?

 

FolderSizeAlan-2.jpg

Link to comment
Share on other sites

Hi Terry,

 

I hope these clarifications help.

 

Quote

Will the macro always start in a folder, with one of its subfolders selected, as you imply? Or could the target be the current folder?

Make the macro act on the one folder a user has selected in File Explorer.

 

Quote

How will the client select the target?

 

He uses two methods to select files and folders in Windows File Explorer.

 

1. Press arrow keys; and

 

2. Use the incremental search built-into the list view: quickly type the first characters of the file or folder he wants to reach

 

For both methods, it helps if File Explorer "View" is set to "Details." (Changing the view is not mandatory, but screen reader navigation is generally easier if the folder view is set to either "Details" or "List.")

 

Quote

What limitations are there on what JAWS can read out?

For the purpose of this challenge, there's no need to deep-dive into Jaws capabilities. So my answer is a simplification: Jaws can easily read text that can be given focus as a result of pressing sequences of: the four arrow keys; Tab; the alphanumeric keys; space bar; Enter; Shift, Ctrl, and Alt; and a handful of other keys.

Applied to File Explorer: use the arrow keys to navigate through the list of folders. Press Enter to open a folder.

 

It's not possible to use these keys to give focus to a tooltip. So Jaws cannot easily read tooltips. (It can be done… but it's complex!)

 

Quote

And will the client be happy to use the macro successively, rather than a columnar display of folders, such as the TreeSize suggestion I made?

Jaws can read columnar information in applications that have been designed with accessibility in mind. Not sure TreeSize is one of those! And even if it was, and even if my client might be better served by switching to a better file manager, the challenge is to come up with a solution for File Explorer! :)

Link to comment
Share on other sites

Terry, your solution is similar to my first attempt. My script worked nicely. With use, I discovered three circumstances that caused my script to fail:


1. The time to populate the "Size" field ranges from almost instantaneously, to ten or more seconds. The lag is related to the number of subfolders and files that are inside the folder.

 

2. The layout of various "Properties" screens differs, which means the "Size" field isn't always in the same place. So clicking on fixed coordinates sometimes succeeds, sometimes fails.

 

3. There is at least one "Properties" screen that doesn't allow fields to be selected! Argg!!

 

I think I solved the first and second failures, but the third may not be amenable to a solution based on grabbing information from the Properties screen. The alternative technique originally suggested by rberq is starting to look more and more appealing.

Link to comment
Share on other sites

Hi Terry,


My original version used <ALT><ENTER> to open the "Properties" window instead of a simulated right click; and my version clicks in the centre of the "Size" field and presses <HOME><SHIFT><END> to select the field. Otherwise, our scripts are more-or-less identical. (This is a good example of great minds thinking alike! :) )

 

Based on the similarity of our scripts, I'm confident that yours will not report accurate information when you request the size of a folder that contains many subfolders and files. Try it, for example, with c:\Windows

 

Also, compare the results with any of the folders that are here:

 

C:\Users\[your user name]

 

with any of the folders that are here:

 

C:\Users\[your user name]\Documents

 

My current solution has workarounds for these kinds of problems... but dammit, I will try a solution based on DOS commands!

 

Link to comment
Share on other sites

You're right, very slow: 15 s for my 29 GB C:\Windows folder. Which my macro hadn't allowed for, with no test to determine when counting had finished.

 

Look forward to seeing your fastest version, perhaps using command prompts or PowerShell.

Link to comment
Share on other sites

On 3/20/2021 at 8:27 AM, rberq said:

The macro can issue a DOS-style command directing its output to a file.  For this problem, the command would be DIR DIRPATH  /S  >C:\Temp\filelist.txt, which lists all files in the specified folder and in all subfolders.  The macro can then read and process filelist.txt, whose next-to-last line contains the cumulative number and size of the files.  I

 

OK, I give up! Using Macro Express, how did you shell out to the prompt AND send a command to the command line AND exit cmd.exe?

Link to comment
Share on other sites

Sorry, I expressed that badly when I referred to the macro issuing a DOS command.

 

The macro can:

(1) Delete any existing file C:\Temp\Temp.bat

(2) Build a new file C:\Temp\Temp.bat containing the DIR command -- last command of the .bat file should be "exit"

(3) Program Launch C:\Temp\Temp.bat

(4) Text File Begin Process to read back and process C:\Temp\filelist.txt (output of DIR command)

 

The sample below works to create and run the batch command file.  I haven't coded the Text File Process step to read back the report file.  It may need some code after launching the batch file -- a delay at the very least -- to determine when the report file is ready to process. 

 

//  
Delete File/Files: "c:\temp\test.bat"
Variable Set String %line% to "cd\"
Variable Modify String: Append %line% to text file, "c:\temp\test.bat"
Variable Set String %line% to "dir c:\onedrive /s > c:\temp\filelist.txt"
Variable Modify String: Append %line% to text file, "c:\temp\test.bat"
Variable Set String %line% to "exit"
Variable Modify String: Append %line% to text file, "c:\temp\test.bat"
Program Launch: "test.bat" (Normal)
Parameters:
Macro Return
//  

 

Link to comment
Share on other sites

I consider this an interim solution... the shell method seems like it would be far less flaky. Nevertheless, it's fun to witness this macro monitoring the "Size" field...

 

// In File Explorer, display the size of the selected folder in a message box
// Set File Explorer to display the full path in the title bar!
 
// Start with a *folder* selected in File Explorer -- selecting a file may or may not work
Text Type (Simulate Keystrokes): <ALT><ENTER> // Open Properties for the selected item
Delay: 500 milliseconds // Wait for the Properties screen to open
 
Variable Set String %WinTitle% to topmost window title // Get the full path from the title bar
 
If Variable %WinTitle% Contains "OS (" // The script cannot handle this situation!
  MessageBox: Cannot get the size!
  Macro Stop
End If
 
// Prepare to click in the centre of the "Size" field.
// The centre of the "Size" field, horizontally, is about 45% of the screen width from the left edge.
// But the vertical position varies. Depending on which Properties window opens...
// ...the "Size" field can be in one of two locations: 37% or 40% of the distance from the top.
// So set a "fudge factor" based on the window title and calculate the y-coordinate.
Variable Set Decimal %FudgeFactor% to 0.37 // This is the most common fudge factor
If Variable %WinTitle% Equals "Documents Properties"
  OR
If Variable %WinTitle% Equals "Music Properties"
  OR
If Variable %WinTitle% Equals "Videos Properties"
  OR
If Variable %WinTitle% Equals "Pictures Properties"
  Variable Set Decimal %FudgeFactor% to 0.4
End If
 
// Calculate where to click relative to the height and width of a "Properties" screen
Variable Set Integer %Width%: Set to the Current Window's Width
Variable Set Integer %Height%: Set to the Current Window's Height
 
Variable Modify Integer %Width%: Convert to Decimal (%WidthDecimal%)
Variable Modify Integer %Height%: Convert to Decimal (%HeightDecimal%)
 
Variable Modify Decimal: %TargetXDecimal% = %WidthDecimal% * 0.45
Variable Modify Decimal: %TargetYDecimal% = %HeightDecimal% * %FudgeFactor%
 
Variable Modify Decimal %TargetXDecimal%: Truncate to Integer (%TargetXInteger%)
Variable Modify Decimal %TargetYDecimal%: Truncate to Integer (%TargetYInteger%)
 
// Check once a second for 20 seconds to see if the "Size" field has changed
Variable Set String %FieldCapture2% to ""
 
Repeat Start (Repeat 20 times)
  Mouse Move: %TargetXInteger%, %TargetYInteger% Relative to Current Window // Centre of the "Size" field
  Mouse Left Click
  Text Type (Simulate Keystrokes): <HOME><SHIFT><END> // Select the field
  Text Type (Simulate Keystrokes): <CONTROL>c
  Delay: 50 milliseconds
  Variable Set String %FieldCapture1% from the clipboard contents
  Delay: 50 milliseconds
   
  If Variable %FieldCapture1% Equals "%FieldCapture2%" // Are values equal after consecutive loops? Then done!
    Text Type (Simulate Keystrokes): <ESC> // Close the "Properties" window
    MessageBox: Size of Folder
    Macro Stop
  End If
  Variable Set String %FieldCapture2% to "%FieldCapture1%"
  Delay: 1000 milliseconds
End Repeat
MessageBox: Best Guess of the Size of Folder

  
<COMMENT Value="In File Explorer, display the size of the selected folder in a message box"/>
<COMMENT Value="Set File Explorer to display the full path in the title bar!"/>
<COMMENT/>
<COMMENT Value="Start with a *folder* selected in File Explorer -- selecting a file may or may not work"/>
<TEXT TYPE Action="0" Text="<ALT><ENTER>" _COMMENT="Open Properties for the selected item"/>
<DELAY Flags="\x02" Time="500" _COMMENT="Wait for the Properties screen to open"/>
<COMMENT/>
<VARIABLE SET STRING Option="\x05" Destination="%WinTitle%" _COMMENT="Get the full path from the title bar"/>
<COMMENT/>
<IF VARIABLE Variable="%WinTitle%" Condition="\x06" Value="OS (" IgnoreCase="FALSE" _COMMENT="The script cannot handle this situation!"/>
<MESSAGEBOX Caption="Cannot get the size!" Message="This script doesn't work in \"%WinTitle%\"!" Icon="4"/>
<MACRO STOP/>
<END IF/>
<COMMENT/>
<COMMENT Value="Prepare to click in the centre of the \"Size\" field."/>
<COMMENT Value="The centre of the \"Size\" field, horizontally, is about 45% of the screen width from the left edge."/>
<COMMENT Value="But the vertical position varies. Depending on which Properties window opens..."/>
<COMMENT Value="...the \"Size\" field can be in one of two locations: 37% or 40% of the distance from the top."/>
<COMMENT Value="So set a \"fudge factor\" based on the window title and calculate the y-coordinate."/>
<VARIABLE SET DECIMAL Option="\x00" Destination="%FudgeFactor%" Value="0.37" _COMMENT="This is the most common fudge factor"/>
<IF VARIABLE Variable="%WinTitle%" Condition="\x00" Value="Documents Properties" IgnoreCase="FALSE"/>
<OR/>
<IF VARIABLE Variable="%WinTitle%" Condition="\x00" Value="Music Properties" IgnoreCase="FALSE"/>
<OR/>
<IF VARIABLE Variable="%WinTitle%" Condition="\x00" Value="Videos Properties" IgnoreCase="FALSE"/>
<OR/>
<IF VARIABLE Variable="%WinTitle%" Condition="\x00" Value="Pictures Properties" IgnoreCase="FALSE"/>
<VARIABLE SET DECIMAL Option="\x00" Destination="%FudgeFactor%" Value="0.4"/>
<END IF/>
<COMMENT/>
<COMMENT Value="Calculate where to click relative to the height and width of a \"Properties\" screen"/>
<VARIABLE SET INTEGER Option="\x0A" Destination="%Width%"/>
<VARIABLE SET INTEGER Option="\x0B" Destination="%Height%"/>
<COMMENT/>
<VARIABLE MODIFY INTEGER Option="\x05" Destination="%Width%" Variable="%WidthDecimal%"/>
<VARIABLE MODIFY INTEGER Option="\x05" Destination="%Height%" Variable="%HeightDecimal%"/>
<COMMENT/>
<VARIABLE MODIFY DECIMAL Option="\x02" Destination="%TargetXDecimal%" Value1="%WidthDecimal%" Value2="0.45"/>
<VARIABLE MODIFY DECIMAL Option="\x02" Destination="%TargetYDecimal%" Value1="%HeightDecimal%" Value2="%FudgeFactor%"/>
<COMMENT/>
<VARIABLE MODIFY DECIMAL Option="\x06" Destination="%TargetXDecimal%" Variable="%TargetXInteger%"/>
<VARIABLE MODIFY DECIMAL Option="\x06" Destination="%TargetYDecimal%" Variable="%TargetYInteger%"/>
<COMMENT/>
<COMMENT Value="Check once a second for 20 seconds to see if the \"Size\" field has changed"/>
<VARIABLE SET STRING Option="\x00" Destination="%FieldCapture2%" NoEmbeddedVars="FALSE"/>
<COMMENT/>
<REPEAT START Start="1" Step="1" Count="20" Save="TRUE" Variable="%Count%"/>
<MOUSE MOVE Option="\x02" X="%TargetXInteger%" Y="%TargetYInteger%" Control="%PropertyControl%" _PROMPT="0x000A" _COMMENT="Centre of the \"Size\" field"/>
<MOUSE LEFT CLICK/>
<TEXT TYPE Action="0" Text="<HOME><SHIFT><END>" _COMMENT="Select the field"/>
<TEXT TYPE Action="0" Text="<CONTROL>c"/>
<DELAY Flags="\x02" Time="50"/>
<VARIABLE SET STRING Option="\x02" Destination="%FieldCapture1%" NoEmbeddedVars="FALSE"/>
<DELAY Flags="\x02" Time="50"/>
<COMMENT/>
<IF VARIABLE Variable="%FieldCapture1%" Condition="\x00" Value="%FieldCapture2%" IgnoreCase="FALSE" _COMMENT="Are values equal after consecutive loops? Then done!"/>
<TEXT TYPE Action="0" Text="<ESC>" _COMMENT="Close the \"Properties\" window"/>
<MESSAGEBOX Caption="Size of Folder" Message="%FieldCapture1%\r\n\r\n(Iterations: %Count%)" Icon="2"/>
<MACRO STOP/>
<END IF/>
<VARIABLE SET STRING Option="\x00" Destination="%FieldCapture2%" Value="%FieldCapture1%" NoEmbeddedVars="FALSE"/>
<DELAY Flags="\x02" Time="1000"/>
<END REPEAT/>
<MESSAGEBOX Caption="Best Guess of the Size of Folder" Message="%FieldCapture1%\r\n\r\n(Iterations: %Count%)" Icon="2"/>

 

Link to comment
Share on other sites

2 hours ago, acantor said:

it's fun to witness this macro monitoring the "Size" field...

Yes, always fun watching a macro follow your instructions in real time.  I think robotics would be fun for the same reason -- program your own Mars Rover to navigate the back yard.  Here's another method that might be fun to try: Have your script take a screen shot of the Properties window, pass it to text-recognition software, then parse and read out the results. 

Link to comment
Share on other sites

43 minutes ago, rberq said:

Here's another method that might be fun to try: Have your script take a screen shot of the Properties window, pass it to text-recognition software, then parse and read out the results. 

 

:) Can't wait for someone to try this method!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...