Would someone please get me started with Automator and/or AppleScript. I've gotten more than a little frustrated with it. I'd like to take a very large folder of files (thousands), in a predetermined order (perhaps by name or by date) and move them into subfolders, each of which is no more than a specified size (probably 4.7GB). I don't want ISOs or DMGs or anything just my files nicely split into disk size chunks. No reshuffling of the order either. If a disk only fits a single 10MB file because the next one would blow the limit then so be it. No file will be bigger than the limit either in case your wondering - they will be up to about 50MB tops.
So far I've got a Folder Action with Get Selected Finder Items followed by this AppleScript
on run {input, parameters}
return first item of input
end run
That gets me the first item. I can create a folder e.g. Disk 1 too. And I can move the file also. But how can I work out whether to move to this folder or if it's time for a new folder to be created?
I'd like to do this in Automator if possible, but suspect I'll need a little AppleScript. I'm sure this problem has been solved already, so please just link me if you can. Thanks.
Heres a working AppleScript that will do this. It's imperfect but gets the job done.
It can be very slow with lots of files, I'm sure it can be improved though. High performance is not one of Applescript's strengths.
tell application "Finder"
set files_folder to folder POSIX file "/Users/MonkeyMan/Desktop/MyMessOfFiles"
set destination_folder to folder POSIX file "/Users/MonkeyMan/Desktop/SortedFiles"
set target_size to 250.0 -- size limit your after in MB.
set file_groupings to {} -- list we will store our stuff in
set current_files to {} -- list of the current files we are adding size
set total_files to the count of files in files_folder
set current_size_count to 0
repeat with i from 1 to total_files
set file_size to (the size of file i of files_folder) / 1024.0 / 1024.0 -- convert to MB to help prevent overrunning what the variable can hold
if ((current_size_count + file_size) ≥ target_size) then
-- this will overrun our size limit so store the current_files and reset the counters
set the end of file_groupings to current_files
set current_files to {}
set current_size_count to 0
end if
set current_size_count to current_size_count + file_size
set the end of current_files to (a reference to (file i of files_folder) as alias)
if (i = total_files) then
-- its the last file so add the current files disreagarding current size
copy current_files to the end of file_groupings
end if
end repeat
-- Copy the files into sub folders
set total_groups to the count of file_groupings
repeat with i from 1 to total_groups
set current_group to item i of file_groupings
set dest_folder to my ensureFolderExists(("disk " & i), destination_folder)
move current_group to dest_folder
end repeat
end tell
say "finished"
on ensureFolderExists(fold_name, host_folder)
tell application "Finder"
if not (exists folder fold_name of host_folder) then
return make new folder at host_folder with properties {name:fold_name}
else
return folder fold_name of host_folder
end if
end tell
end ensureFolderExists
Related
I have some code that uses an array with network path location and then pulls information about files in each path.
The problem is the code is VERY slow. I have realized that the main problem is reaching over the network 3 times for each file. 1 time to find the file name, a 2nd time to grab the last modified file date and a 3rd time to capture the file size. IS there a way to grab all this info with one sweep to speed things up?
Thank you :)
For i = 0 To UBound(x)
file = Dir(x(i))
While file <> vbNullString
fileModDate = FileDateTime(x(i) & file)
FILESIZE = FileLen(x(i) & file)
Wend
Next i
I am making an application using Cocoa-Applescript which identifies local IP addresses which are up and running, by pinging x.y.z.[1-255] and appends running IPs to a text file. I already have a GUI for choosing x, y and z and have already made the script to ping each address:
repeat 255 times
try
do shell script "ping -o -t 1 -c 1 " & ipstamp & num4
do shell script "echo " & ipstamp & num4 & " >>/Users/DJ/Desktop/GoodIPs.txt"
end try
set num4 to (num4 + 1)
end repeat
Where ipstamp is x.y.z and num4 is the [1-255]. But now I want a progress indicator to show where it is up to in the process. I know how to get an indeterminate indicator which simply starts and stops:
ProgressBar's startAnimation_(ProgressBar)
## code to ping IP address
ProgressBar's stopAnimation_(ProgressBar)
But that is only indeterminate and I can not find any info on setting determinate ones in Cocoa-Applescript, setting their maximum steps and setting their current step - much like in regular Applescript's:
set progress total steps to x
set progress completed steps to y
Except it is in the GUI, and so i need to use NSProgressIndicators to do it. So summed up, how do you make a determinate progress bar, how do you set its total steps and how do you update its current step?
EDIT
It can be changed to determinate in the menu builder's Attribute Inspector, as can max, min and current steps. However I do need to be able to change the maximum and current steps from within the script, so those still apply.
Well you can make a Determinate progress indercator but the problem is you have to repeat telling it to go to a certain lenght by using the
setDoubleValue_()
message, but anyway here is a simple script to tell it to go to go up to 100
property MyProgressBar : missing value -- Progress Bar IB Outlet
on applicationWillFinishLaunching_(aNotification)
set c to 0
repeat 100 times
set c to c + 1
delay 0.2
tell MyProgressBar to setDoubleValue_(c) -- Tells Progress bar the % to go to
if c > 99 then
exit repeat -- If current repeat is 100 or more then cancels adding more
end if
end repeat
end applicationWillFinishLaunching_
Hope this helped!
just do:
set progress total steps to -1
-- do something
set progress total steps to 0
Remember, that the visualization depends on how the script is executed.
I am currently using Diadem to process a large amount of data.
There is a specific treatment that I must do on a large number of files. Therefore, I have a script loading each file one by one to do this every time.
The thing is, after several hours of computation, I get an error : Incorrect instruction or user command. In <DataFileHeaderAccess.VBC> (line:1328, column:5): Unable to conect to the specified server.
By this time, it will have successfully passed the portion of code where it happens several times, and if I launch it back on the file that has issues, it will not fail (not for this file at least).
Even more strange is that nothing is done remotely there, so I have no idea which server it might be talking about. And the file is ot opened elsewhere. Most of the time, it happens when I'm not even in the office.
And finally, I managed to find nothing anywhere regarding this issue, And I'm growing quite desperate to manage to solve it.
So ... Simple question ... "Help ?".
Well, let's develop it a little :
What might be the cause of this issue ?
How can I solve it ?
Here is the portion of code incriminated if it might help :
Function TryLoadGroup(sPath, sFileName, sGroupName, sNewGroupName)
Dim oDataFileHeader, oImportedGroup
Set oDataFileHeader = DataFileHeaderAccess(sPath & sFileName, "TDM", True)
Dim iLoop, bRet
For iLoop = 1 To oDataFileHeader.GroupCount
If oDataFileHeader.GroupNameGet(iLoop) = sGroupName Then
bret = True
End If
Next
oDataFileHeader.Close(False)
If bRet Then
Set oImportedGroup = DatafileLoadSel(sPath & sFileName,"TDM", sGroupName & "/*")
oImportedGroup.Item(1).Name = sNewGroupName
Set TryLoadGroup = oImportedGroup
Else
Set TryLoadGroup = Data.CreateElementList
End If
End Function
Set oDataFileHeader = DataFileHeaderAccess(sPath & sFileName, "TDM", True)
The error message just means that it is not capable to open the file.
There are some things I can think of
The file is corrupt (but this seems not to be true because you can open it)
The file is opened by DIAdem or a group of it is already loaded into DIAdem
DIAdem has run out of memory
Potentially you should put an error handler arround your inner loop
on error goto 0
' call a method
if 0 <> err.number then
LogFileWrite "Unable to insert file '" & filename & "': " & err.description
end if
on error goto 0
This will allow you to go on processing and see the error in the DIAdem Logfile later on.
Today I am trying to remove some bytes from an EXE file.
Inside the EXE I found a path to a file that the EXE needs to load. I want to change the path, and to do that I have to remove some ../../ characters. When I do that and save the file, it looses its icon and a 'win32 unknow format error' is displayed when I try to execute it.
If I don't remove those bytes but replace them by 0, the icon is not lost, and the file looks right. Yet, the path is incorrect.
So, it looks like when I remove bytes, position of other information inside the file is lost, including resources (the icon). After removeing those bytes, I need to add other 6 bytes, to keep the same size and position of other data. Where should I do that? If I add those bytes at the end of the file, it doesn't work. Could you give me some clues? Thanks!
After removing the ../../ from the start of the string, stick six 0 bytes at the end of the string (I'm assuming you can identify the end manually). That way the offset of everything in the file remains the same. By removing the 6 bytes entirely, the offset of things after the string would change. By replacing the 6 bytes with 0s, the offset of the string would change (it would now really be at wherever it was + 6).
I need to rename and fill about 70 USB sticks. Having an Applescript run automatically when they are inserted would make it much simpler.
Any external drive you connect to an OS X machine is mounted into /Volumes. If you watch that folder for changes, you can pick up on added external drives and process these. Running this code:
property ignoredVolumes : {"Macintosh HD", "Time Machine Backups"} -- add as needed
tell application "System Events"
set rootVolume to disk item (POSIX file "/Volumes" as text)
set allVolumes to name of every disk item of rootVolume
repeat with aVolume in allVolumes
if aVolume is not in ignoredVolumes then
set name of disk item (path of rootVolume & aVolume) to newName
end if
end repeat
end tell
will rename drives that are not in your ignoredVolumes list (unplug all but those you want to ignore, run ls /Volumes in Terminal and add the names to the property) to newName. To have this triggered on every change, modify the codes to be a Stay-Open script application:
property pollIntervall : 60 -- in seconds
property ignoredVolumes : {…} -- from above
on run
my checkVolumes()
end run
on idle
my checkVolumes()
return pollInterval
end idle
on checkVolumes()
tell … end tell -- from above
end checkVolumes
and save it in AppleScript Editor (select “AppleScript application”, make sure you tick “Stay Open” when you do). Once launched, the script will keep running, executing the on idle handler every pollInterval seconds.
This will do fine if you are basically doing a once-in-a-while batch job. If you want a more permanent solution that does not rely on running a stay-open script application, you can either
attach a Folder Action Script to the /Volumes folder (hat tip to Philip Regan on Ask Different; details on how to configure the action in this Mac OS X Hints post) – the advantage being you strictly process additions to /Volumes, or
use launchd by creating a LaunchAgent with the StartOnMount key set to true – that will trigger the script / app the agent starts every time a filesystem is mounted (tip of the hat to Daniel Beck at Ask Different; see Apple’s Technical Note TN2083 for the gory details).