Jump to content

File Properties strange behavior


meisandy
 Share

Recommended Posts

Hi All

I'm trying to write a script that indexes all the mp3's and wav's in a directory.

I'm using this command line to get all the files in a root directory

RunWait(@ComSpec & "/c dir " & $FOLDER & $WILDCARDS & ' /b/s > ' & @TempDir & '\list.tmp', "", @SW_HIDE)
More info here

And I'm using Melba's file get property COM script to get the artist and album etc

But, sometimes it errors where the varible $oDir is! {

The requested action with this object has failed.:
Local $oFile = $oDir.Parsename ($sFile)
Local $oFile = $oDir.Parsename ($sFile)^ ERROR

}

I worked out that if a string contains character's like "é" it won't accept it but theres one set of tracks that I can't see any errors with: for example

"F:\Sound of the 80's\Disc 1 - Sounds Of The 80’s - 1980\Blondie - Call Me.mp3"

But it does still error?

Any Reasons?

Please help asap

DjATUit

UPDATE: If I just scan the set of tracks on their own, it works, even if the track/directory contains character like "é". But in a loop where previous tracks have been scanned, it doesn't work!

Edited by DjATUit
Link to comment
Share on other sites

  • Moderators

DjATUit,

Hi again! ;)

Let us try some errorchecking. Use ConsoleWrite to check the value you are actually passing to the .Parsename command against the original file name you pass to the function and see if there are any differences. :)

I would copy the problem files into their own folder first and just loop through that as SciTE will explode if you ask it to ConsoleWrite all of your 36000 music files. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Hi M23

Thanks for replying, I couldn't figure out why the ConsoleWrite wouldn't work (You've explained it) so I've been using TrayTip instead.

I've done some error checking anyway, and this is where the "strange behavior" bit comes in!:

It works if you just scan the single file? But when you include it in the loop it doesn't work?

Any Idea's

Link to comment
Share on other sites

  • Moderators

DjATUit,

Code? ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Sorry, might help might it ;)

If StringRight($Root, 1) <> "\" Then $Root = $Root & "\"
;~  MsgBox(0, "cmd", @ComSpec & " /c dir " & $Root & $Extension & " /b/s > " & @TempDir & "\list.tmp")
    RunWait(@ComSpec & " /c dir " & $Root & $Extension & " /b/s > " & @TempDir & "\list.tmp", "", @SW_SHOW)
    $Files = StringSplit(StringReplace(FileRead(@TempDir & "\list.tmp", FileGetSize(@TempDir & "\list.tmp")), @LF, ""), @CR)
    For $i = 1 To $Files[0]-1;-21000
        If StringRight($Files[$i], 4) = ".mp3" Or StringRight($Files[$i], 4) = ".wav" Then
            Local $oShellApp = ObjCreate("shell.application")
            If IsObj($oShellApp) = 1 Then
                OnAutoItExitRegister("ErrorMsg")
                $sFile = StringTrimLeft($Files[$i], StringInStr($Files[$i], "\", 0, -1))
                $sDir = StringTrimRight($Files[$i], (StringLen($Files[$i]) - StringInStr($Files[$i], "\", 0, -1)))
                TrayTip("COM", $sDir & $sFile, 5)
                Local $oDir = $oShellApp.NameSpace ( $sDir )
;~              MsgBox(0, $sDir, $oDir);
                If @error Then ContinueLoop
                Local $oFile = $oDir.Parsename ($sFile)$URow = UBound($Array)
                _Add2DString($oDir.GetDetailsOf($oFile, 0), $oDir.GetDetailsOf($oFile, 0), $URow, 0)
                _Add2DString($oDir.GetDetailsOf($oFile, 0), $sDir, $URow, 1)
                _Add2DString($oDir.GetDetailsOf($oFile, 0), $oDir.GetDetailsOf($oFile, 14), $URow, 2, "Undefined")
                _Add2DString($oDir.GetDetailsOf($oFile, 0), $oDir.GetDetailsOf($oFile, 13), $URow, 3, "Various")
                _Add2DString($oDir.GetDetailsOf($oFile, 0), $oDir.GetDetailsOf($oFile, 27), $URow, 4)
                _Add2DString($oDir.GetDetailsOf($oFile, 0), $oDir.GetDetailsOf($oFile, 16), $URow, 5, "Undefined")
                _Add2DString($oDir.GetDetailsOf($oFile, 0), StringRight($files[$i], 4), $URow, 6)
            EndIf
        EndIf
    Next

I just want to focus on the loop and getting properties; The bit that goes wrong is $oDir.NameSpace ( $sDir ) and the error says something like bad object request?

So, I'd appriciate it if you didn't critise anything else other than the bit thats going wrong

Edited by DjATUit
Link to comment
Share on other sites

  • Moderators

DjATUit,

If you look at the code I posted to do this, you will see the following:

Local $sDir_Name = StringRegExpReplace($sPassed_File_Name, "(^.*\\)(.*)", "\1")
Local $sFile_Name = StringRegExpReplace($sPassed_File_Name, "^.*\\", "")

Local $sDOS_Dir = FileGetShortName($sDir_Name, 1) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


; And then
Local $oDir = $oShellApp.NameSpace($sDOS_Dir) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

You seem to be missing the FileGetShortName line which might well be the cause of your problems with these particular files. Give it a try. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Thank you for wanting to help Varian

I can't really post the whole script. But:

Here is my scan function:

$Root =FileSelectFolder("Select a folder","")
$Extension = ""
$LeftCount = StringInStr($Root, "\", 0, -1)
    If StringRight($Root, 1) <> "\" Then $Root = $Root & "\"
;~  MsgBox(0, "cmd", @ComSpec & " /c dir " & $Root & $Extension & " /b/s > " & @TempDir & "\list.tmp")
    RunWait(@ComSpec & " /c dir " & $Root & $Extension & " /b/s > " & @TempDir & "\list.tmp", "", @SW_SHOW)
    $Files = StringSplit(StringReplace(FileRead(@TempDir & "\list.tmp", FileGetSize(@TempDir & "\list.tmp")), @LF, ""), @CR)
    For $i = 1 To $Files[0]-1;-21000
        If StringRight($Files[$i], 4) = ".mp3" Or StringRight($Files[$i], 4) = ".wav" Then
            Local $oShellApp = ObjCreate("shell.application")
            If IsObj($oShellApp) = 1 Then
;~              OnAutoItExitRegister("ErrorMsg")
;~              $sFile = StringTrimLeft($Files[$i], StringInStr($Files[$i], "\", 0, -1))
;~              $sDir = StringTrimRight($Files[$i], (StringLen($Files[$i]) - StringInStr($Files[$i], "\", 0, -1)))
                Local $sDir = StringRegExpReplace($Files[$i], "(^.*\\)(.*)", "\1")
                Local $sFile = StringRegExpReplace($Files[$i], "^.*\\", "")

                Local $sDOS_Dir = FileGetShortName($sDir, 1) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

                TrayTip("COM", $sDir & $sFile, 5)
                Local $oDir = $oShellApp.NameSpace ( $sDOS_Dir )
;~              MsgBox(0, $sDir, $oDir);
                Local $oFile = $oDir.Parsename ($sFile)
                $URow = UBound($Tracks)
                _2DArrayAdd($Tracks, $oDir.GetDetailsOf($oFile, 0), $URow, 0)
                _2DArrayAdd($Tracks, $sDir, $URow, 1)
                _2DArrayAdd($Tracks, $oDir.GetDetailsOf($oFile, 14), $URow, 2, "Undefined")
                _2DArrayAdd($Tracks, $oDir.GetDetailsOf($oFile, 13), $URow, 3, "Various")
                _2DArrayAdd($Tracks, $oDir.GetDetailsOf($oFile, 27), $URow, 4)
                _2DArrayAdd($Tracks, $oDir.GetDetailsOf($oFile, 16), $URow, 5, "Undefined")
                _2DArrayAdd($Tracks, StringRight($files[$i], 4), $URow, 6)

Here is my _2DArrayAdd function:

Func _2DArrayAdd(ByRef $avArray, $vValue, $x, $y, $rText = "")
    If $vValue = "" Then $vValue = $rText
    If $x > UBound($avArray)-1 Then
        ReDim $avArray[$x+1][UBound($avArray, 2)]
    EndIf
    If $y > UBound($avArray, 2)-1 Then
        ReDim $avArray[UBound($avArray)][$y+1]
    EndIf
    $avArray[$x][$y] = $vValue
    Return True
EndFunc

And Here is how I declare $Tracks (changed from $Array):

Dim $Tracks[1][7] = [["Track", "Path", "Album", "Artist", "Length", "Genre", "Extension"]]

PS Please excuse any messy code!

EDIT: But as I said before the problem is not with the array functions it's with the COM function to get file properties! Please read this thread thoroughly - I've mentioned it tons of times already!

Edited by DjATUit
Link to comment
Share on other sites

The problem is related to unicode characters in the filenames. You use the MS-DOS dir command and parse the filenames through the console. At that point Windows will use a standard codepage not able to display all unicode characters... take a look at your example:

"F:\Sound of the 80's\Disc 1 - Sounds Of The 80’s - 1980\Blondie - Call Me.mp3"

I'll bet the ’ is parsed from console as ' ...

To obtain clean unicode filenames use one of the many FileListToArray() functions in the examples section (check that it does not rely on the dir-command, but on FileFindFirstFile(), FileFindNextFile() ;))...

Edit:

Damn, even the forum can not distinguish between ’ and ' , copy this line and paste it to "Fast Reply" to see the difference...

Edited by KaFu
Link to comment
Share on other sites

Just an FYI, you can actually use 'dir' to read in Unicode names. You just need to use the /u switch before 'dir', and pipe it to a file. The file then needs to be opened in forced UTF16 little-endian format since there is no BOM created in the file. Check 'mfecteau's and my own post in the thread 'Another _FileListToArray()'. I added the unicode file-read solution in the last post.

Link to comment
Share on other sites

Link to comment
Share on other sites

Hi All

Thanks for replying, what you've said seems to make sense!

But I can't try it because I can't seem to get the /u switch working in command prompt (I haven't tried it using RunWait() in Autoit yet). So can anyone give my the correct command please, because I really want to use the command line way!

Also, will this unicode switch only list capable items or will it still list everything but convert it to a usable format? (if you know what I mean?)

PS I'm running Windows 7 Ultimate x64

Edited by DjATUit
Link to comment
Share on other sites

The "shell.application" object will handle all unicode input, so yes, if you extract unicode input, all files should be processed... at least on your system ;)...

An additional problem might be, that the number, the numbering and the naming of properties acquired with "shell.application" depends on the OS-Version and Language...

[["Track", "Path", "Album", "Artist", "Length", "Genre", "Extension"]]

on your system are defined as follows on mine (German Win-7,64):

[["Titelnummer", "Pfad", "Album", "Mitwirkende Interpreten", "Länge", "Genre", "Extension"]]

... maybe give SMF a shot, under Extdended either check "Ext. File Attributes" or "MediaInfo", should extract all the infos for you :)...

Edited by KaFu
Link to comment
Share on other sites

First of all, Thank you KaFu...

But do you mind me asking, how did you extract the meta data and do a search like the command line because I can't seem to find that bit in your source code (Maybe you can point it out)?

And secondly, now I've put the "/u" in the cmd the stringsplit/fileread line won't work properly. All I get is one letter when I check but if I look at $Files[0] it comes up with loads of files.

BTW : This line:

$Files = StringSplit(StringReplace(FileRead(@TempDir & "\list.tmp", FileGetSize(@TempDir & "\list.tmp")), @LF, ""), @CR)

Anyone?

PS Nice work KaFu

Link to comment
Share on other sites

But do you mind me asking, how did you extract the meta data and do a search like the command line because I can't seem to find that bit in your source code (Maybe you can point it out)?

With the line

$av_ret[$av_ret[0][0]][0] = $objFolder.GetDetailsOf($objFolder.Items, $i)

I extract the names of the properties. I do that one time on start of the search against smf.exe itlself to extract all available properties names, in the search I then extract the property values and can match them to the names. This works regardless of the properties true name (and existence, 40 on my old XP and 266 on Win7), because I extract ALL or nothing :). In the next release of SMF there will be a pre-selection listview (to improve speed, reduce detail overload), which is populated with the query against the exe itself, thus also dynamic and unique to the OS/Lang combination.

And secondly, now I've put the "/u" in the cmd the stringsplit/fileread line won't work properly. All I get is one letter when I check but if I look at $Files[0] it comes up with loads of files.

BTW : This line:

$Files = StringSplit(StringReplace(FileRead(@TempDir & "\list.tmp", FileGetSize(@TempDir & "\list.tmp")), @LF, ""), @CR)

Anyone?

The return of _FileListToArrayEx() is already an array ;), you don't need this line...

PS Nice work KaFu

Thank you ;)...
Link to comment
Share on other sites

And secondly, now I've put the "/u" in the cmd the stringsplit/fileread line won't work properly. All I get is one letter when I check but if I look at $Files[0] it comes up with loads of files.

BTW : This line:

$Files = StringSplit(StringReplace(FileRead(@TempDir & "\list.tmp", FileGetSize(@TempDir & "\list.tmp")), @LF, ""), @CR)

Reread my last post in that thread I linked to. There is no BOM in unicode file output from DOS commands, which means 'FileRead' by itself will interpret the file as plain ASCII text, and stop at the first 'NULL' terminator it comes across. Since UTF16 unicode output is 2-bytes each, it needs to be read in as, or converted to unicode UTF16. But ah, all that's covered in that thread.
Link to comment
Share on other sites

Reading Ascend4nts reply... I reread your code sample too ;). I assumed you already used _FileListToArrayEx(). Better use that function directly instead of trying to code you own. Fetch a filelist and process that. Heres the function:

; Example Start
#include <array.au3> ; for example only
$aFiles = _FileListToArrayEx(@ScriptDir, "*.*", 0, -1, True, True, True)
_ArrayDisplay($aFiles)
; Example End

Func _FileListToArrayEx($s_path, $s_mask = "*.*", $i_flag = 0, $s_exclude = -1, $f_recurse = False, $f_full_path = False, $unicode_support = False)
    ; By mfecteau & Ascend4nt
    ; http://www.autoitscript.com/forum/index.php?showtopic=33930&st=60&p=799369&#entry799369

    If FileExists($s_path) = 0 Then Return SetError(1, 1, 0)

    ; Strip trailing backslash, and add one after to make sure there's only one
    $s_path = StringRegExpReplace($s_path, "[\\/]+\z", "") & "\"

    ; Set all defaults
    If $s_mask = -1 Or $s_mask = Default Then $s_mask = "*.*"
    If $i_flag = -1 Or $i_flag = Default Then $i_flag = 0
    If $s_exclude = -1 Or $s_exclude = Default Then $s_exclude = ""

    ; Look for bad chars
    If StringRegExp($s_mask, "[/:><\|]") Or StringRegExp($s_exclude, "[/:><\|]") Then
        Return SetError(2, 2, 0)
    EndIf

    ; Strip leading spaces between semi colon delimiter
    $s_mask = StringRegExpReplace($s_mask, "\s*;\s*", ";")
    If $s_exclude Then $s_exclude = StringRegExpReplace($s_exclude, "\s*;\s*", ";")

    ; Confirm mask has something in it
    If StringStripWS($s_mask, 8) = "" Then Return SetError(2, 2, 0)
    If $i_flag < 0 Or $i_flag > 2 Then Return SetError(3, 3, 0)

    ; Validate and create path + mask params
    Local $a_split = StringSplit($s_mask, ";"), $s_hold_split = ""
    For $i = 1 To $a_split[0]
        If StringStripWS($a_split[$i], 8) = "" Then ContinueLoop
        If StringRegExp($a_split[$i], "^\..*?\..*?\z") Then
            $a_split[$i] &= "*" & $a_split[$i]
        EndIf
        $s_hold_split &= '"' & $s_path & $a_split[$i] & '" '
    Next
    $s_hold_split = StringTrimRight($s_hold_split, 1)
    If $s_hold_split = "" Then $s_hold_split = '"' & $s_path & '*.*"'

    Local $i_pid, $s_stdout, $s_hold_out, $s_dir_file_only = "", $s_recurse = "/s "
    If $i_flag = 1 Then $s_dir_file_only = ":-d"
    If $i_flag = 2 Then $s_dir_file_only = ":D"
    If Not $f_recurse Then $s_recurse = ""

    If $unicode_support Then
        Dim $command = @ComSpec & " /u /c dir /b " & $s_recurse & "/a" & $s_dir_file_only & " " & $s_hold_split & " > " & @TempDir & "\autoit_mf.tmp"
        $i_pid = RunWait($command, "", @SW_HIDE, 4 + 2)
        $hFile = FileOpen(@TempDir & "\autoit_mf.tmp", 32)
        $s_hold_out = FileRead($hFile)
        FileClose($hFile)
        FileDelete(@TempDir & "\autoit_mf.tmp")
    Else
        $i_pid = Run(@ComSpec & " /c dir /b " & $s_recurse & "/a" & $s_dir_file_only & " " & $s_hold_split, "", @SW_HIDE, 4 + 2)
        While 1
            $s_stdout = StdoutRead($i_pid)
            If @error Then ExitLoop
            $s_hold_out &= $s_stdout
        WEnd
    EndIf

    $s_hold_out = StringRegExpReplace($s_hold_out, "\v+\z", "")
    If Not $s_hold_out Then Return SetError(4, 4, 0)

    ; Parse data and find matches based on flags
    Local $a_fsplit = StringSplit(StringStripCR($s_hold_out), @LF), $s_hold_ret
    $s_hold_out = ""

    If $s_exclude Then $s_exclude = StringReplace(StringReplace($s_exclude, "*", ".*?"), ";", "|")

    For $i = 1 To $a_fsplit[0]
        If $s_exclude And StringRegExp(StringRegExpReplace( _
                $a_fsplit[$i], "(.*?[\\/]+)*(.*?\z)", "\2"), "(?i)\Q" & $s_exclude & "\E") Then ContinueLoop
        If StringRegExp($a_fsplit[$i], "^\w:[\\/]+") = 0 Then $a_fsplit[$i] = $s_path & $a_fsplit[$i]
        If $f_full_path Then
            $s_hold_ret &= $a_fsplit[$i] & Chr(1)
        Else
            $s_hold_ret &= StringRegExpReplace($a_fsplit[$i], "((?:.*?[\\/]+)*)(.*?\z)", "$2") & Chr(1)
        EndIf
    Next

    $s_hold_ret = StringTrimRight($s_hold_ret, 1)
    If $s_hold_ret = "" Then Return SetError(5, 5, 0)

    Return StringSplit($s_hold_ret, Chr(1))
EndFunc   ;==>_FileListToArrayEx

Edit:

Don't forget to set unicode support to true (updated sample above).

Edited by KaFu
Link to comment
Share on other sites

Thank you KaFu

Thank you everyone

Sorry for running you around in circles, I know someone mentioned FileListToArrayEx before but I wasn't too keen on using it because it wouldn't be my work. But now I'm using it (everything works great now) because I realised that it's the best way and if I managed to write the function on my own it would end up identical to this UDF, plus how else I'm I going to learn!

So thank you to everyone on this post and the writters of FileListToArrayEx !

DjATUit

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...