Page 1 of 2

How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 9:18 am
by itto
Hi there,

I have the need to create a new folder, no matter what name, just like you would normally do with the OS "new folder" menu entry.

Normally windows creates a new folder named "new folder", and if a folder with that name already exists, an increasing number is added in parentheses afterwards, like "New folder (2)", ecc.

How can I check what is the last free name (with number) available in a specified folder, given the folder name?

I was thinking about checking one by one the files of the directory, until all folders starting with the string "New folder (N)" are checked, then just add +1 to the last N checked.

But this could be a problem for folders with thousand of elements, I don't want to waste resources.

Anyone has a better idea? Perhaps some API entries?

Thanks :)

Re: How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 10:56 am
by IdeasVacuum
Use ExamineDirectory() to list all folders within a folder and then use a regular expression (or find string combo) on each folder name in the list to find post-fixed numbers in parentheses.

Re: How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 1:25 pm
by itto
Ok, this is the solution I came up with, except I chose to match the whole folder name. I was hoping for a OS command to let it create the folder for you, like you would do normally using the OS menus.

Re: How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 5:40 pm
by IdeasVacuum
Hmm, possibly using a little script via RunProgram()

Re: How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 5:43 pm
by ts-soft
I would use a GUID as Directory Name. The code to create a GUID can you extract from this source:
http://www.purebasic.fr/english/viewtop ... 00#p381100

Re: How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 7:26 pm
by VoSs2o0o
A Timestamp is enough....

Code: Select all

Dirname.s = Str(Date())

Re: How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 7:28 pm
by juror
VoSs2o0o wrote:A Timestamp is enough....

Code: Select all

Dirname.s = Str(Date())
Does NOT guarantee uniqueness.

Re: How to create a new folder with a unique name

Posted: Fri Aug 10, 2012 7:44 pm
by itto
Thank you for your replies guys! The problem is that I am creating this folder as a direct consequence of the user action on the file system (I'm enhancing the OS file system commands via additional contextual menus when browsing files and folders), so the name is going to be user friendly and as close as possible as the current OS default name (to not create confusion).

The best would be for the name to be exactly identical to the default system new folder name (thus taking into account the OS language), but I think this is impossible without an OS api or knowing where the default folder name variable is stored in the OS.

edit

by the way thanks ts-soft for the GUID code, it's wonderful and I'll surely use it in many applications! :o

Re: How to create a new folder with a unique name

Posted: Sat Aug 11, 2012 1:06 am
by IdeasVacuum
where the default folder name variable is stored in the OS.
Most likely, that would be stored in the Registry, if it is stored - though I think it probably isn't because it doesn't apply system-wide. Different paths can contain identical folder names (New Folder, New Folder (1) New Folder (2) etc, not the space char between the name and the postfix). It's not impossible to keep a record of it but there isn't a good reason to.

Edit: There is no var. If you create some new folders with any name other than New Folder, then re-name them in sequence, New Folder, New Folder (1) New Folder (2), then create another new folder and let the system name it, the system creates New Folder (3). So, your code can safely create these too.

Re: How to create a new folder with a unique name

Posted: Sat Aug 11, 2012 3:51 am
by kenmo
Something like this?

Code: Select all

Procedure.s UniqueFolder(BasePath.s = "")
  Protected n.i = 1
  
  If (BasePath = "")
    BasePath = GetCurrentDirectory()
  EndIf
  
  While (Not CreateDirectory(BasePath + "New Folder (" + Str(n) + ")"))
    n + 1
  Wend
  
  ProcedureReturn BasePath + "New Folder (" + Str(n) + ")"
EndProcedure

Folder.s = UniqueFolder()

Debug "Created: " + Folder
;DeleteDirectory(Folder, "")

Re: How to create a new folder with a unique name

Posted: Sat Aug 11, 2012 4:30 am
by RASHAD
Using MAC Address

Code: Select all

wsa.WSADATA
*host.HOSTENT

nSize = 32
lpBuffer$ = Space(nSize)
GetComputerName_(@lpBuffer$,@nSize)
If WSAStartup_((1<<8|1), wsa.WSADATA) = #NOERROR
    *host.HOSTENT = gethostbyname_(lpBuffer$)
    WSACleanup_()
    If *host
      IP$ = PeekS(inet_ntoa_(PeekL(PeekL(*host\h_addr_list))))
    EndIf
EndIf

n = 6
Dim MacAddr.b(6)
If SendARP_(inet_addr_(IP$), 0, @MacAddr(0), @n) = #NO_ERROR
  For i = 0 To 5
    MAC$ + RSet(Hex(MacAddr(i)&255),2,"0") 
  Next
EndIf

Txt$ = "F:\"+MAC$
CreateDirectory(Txt$)


Re: How to create a new folder with a unique name

Posted: Sat Aug 11, 2012 11:28 am
by Danilo

Code: Select all

Procedure.s GetNewFolderName()
    Protected index, shell32, name.s
    If OSVersion() >= #PB_OS_Windows_Vista
        index = 16859 ;"New Folder"
    Else
        index = 30320 ;"New Folder"
    EndIf
    
    shell32 = LoadLibrary_("shell32.dll")
    If shell32
        name = Space(1024)
        LoadString_(shell32,index,@name,1024)
        
        FreeLibrary_(shell32)
    EndIf
    ProcedureReturn name
EndProcedure

MessageRequester("New Folder", GetNewFolderName() )


Procedure.s GetUniqueDirectoryName(path.s, template.s)
    Protected fileName.s = path.s+template
    Protected fileNameAddon.s = ""
    For i = 1 To $FFFFFF
        size = FileSize(fileName+fileNameAddon)
        If size = -1
            Break
        Else
            fileNameAddon = " ("+Str(i+1)+")"
        EndIf
    Next
    ProcedureReturn fileName+fileNameAddon
EndProcedure

MessageRequester("New Folder", GetUniqueDirectoryName( "c:\", GetNewFolderName() ) )
Tested:
Win7 64bit english: "New Folder", "New Folder (2)", ...
WinXP Pro 32bit German: "Neuer Ordner", "Neuer Ordner (2)", ...

Re: How to create a new folder with a unique name

Posted: Sat Aug 11, 2012 2:57 pm
by ultralazor

Code: Select all

Procedure.s maked()
  Protected.l fhandle
  Protected.s ff$
  Repeat
    ff$="New Folder "+Str(Random(9999))
    fhandle=ExamineDirectory(#PB_Any,ff$,"*.*")
    If fhandle=0
      CreateDirectory(ff$)
      ProcedureReturn ff$
    Else
      FinishDirectory(fhandle)
    EndIf
  ForEver
EndProcedure

Re: How to create a new folder with a unique name

Posted: Sat Aug 11, 2012 9:12 pm
by itto
Wow guys some really interesting code snippets are coming out here! Thanks!

@kenmo that's exactly the procedure I came up with and am currently using, which is really ok in the end.
Danilo wrote: Tested:
Win7 64bit english: "New Folder", "New Folder (2)", ...
WinXP Pro 32bit German: "Neuer Ordner", "Neuer Ordner (2)", ...
So this must be the same way Windows get the name of the new folder, this is awesome! the name changes according to the language of the OS! :D

Re: How to create a new folder with a unique name

Posted: Sat Aug 11, 2012 9:50 pm
by Danilo
itto wrote:
Danilo wrote: Tested:
Win7 64bit english: "New Folder", "New Folder (2)", ...
WinXP Pro 32bit German: "Neuer Ordner", "Neuer Ordner (2)", ...
So this must be the same way Windows get the name of the new folder, this is awesome! the name changes according to the language of the OS! :D
Yep. But the "magic numbers" changed in Vista.

Here is the code to get the "magic numbers" for the first code (requires UNICODE compilation!):

Code: Select all

;
; http://blogs.msdn.com/b/oldnewthing/archive/2004/01/30/65013.aspx
;
Macro MAKELANGID(p,s)
    ( ( (s)<< 10) | (p) )
EndMacro

Procedure.s FindStringResourceEx(hinst,uId.l, langId.l)
    ;// Convert the string ID into a bundle number
    ;*pwsz = 0
    hrsrc = FindResourceEx_(hinst, #RT_STRING,(uId / 16 + 1)&$FFFF,langId)
    If (hrsrc)
        hglob = LoadResource_(hinst, hrsrc);
        If (hglob)
            *pwsz.Unicode = LockResource_(hglob)
            If (*pwsz)
                *oldResPointer = *pwsz
                i = 0
                While i < (uId & 15)
                    *pwsz = *pwsz + 2 + (*pwsz\u * 2)
                    i+1
                Wend

                If *pwsz\u > 0
                    ret$ = PeekS(*pwsz + 2,*pwsz\u)
                EndIf
                ;UnlockResource_(*oldResPointer)
            EndIf
            FreeResource_(hglob)
        EndIf
    EndIf
    CompilerIf #PB_Compiler_Debugger
        ;If ret$
        ;    Debug ret$
        ;EndIf
    CompilerEndIf
    ProcedureReturn ret$
EndProcedure

Procedure.s FindStringResource(hinst, uId.l)
    ;(LANG_NEUTRAL, SUBLANG_NEUTRAL) = Language Neutral 
    ;(LANG_NEUTRAL, SUBLANG_DEFAULT) = User's Default Language 
    ProcedureReturn FindStringResourceEx(hinst, uId, MAKELANGID(#LANG_NEUTRAL, #SUBLANG_NEUTRAL))
EndProcedure

Procedure FindResourceStringId(resource_handle, string.s, langId)
    resource_id = -1

    For i = 0 To 65536 ;Step 16
        resource_string.s = FindStringResourceEx(resource_handle, i, langId)
        If resource_string
            If resource_string = string
                resource_id=i
                Debug resource_id
                Debug resource_string
                ;Break
            EndIf
        EndIf
        
    Next
    ProcedureReturn resource_id
EndProcedure

shell_handle  = LoadLibrary_("shell32.dll")
new_folder_id = FindResourceStringId(shell_handle, "New Folder", $409); // look for US English "New Folder" resource id.

Debug "-----"

If new_folder_id
    newfolder.s = FindStringResource(shell_handle, new_folder_id)
    ;MessageRequester("New Folder", newfolder )
    Debug newfolder

    Debug FindStringResourceEx(shell_handle, new_folder_id, MAKELANGID(#LANG_GERMAN   ,#SUBLANG_GERMAN) )
    Debug FindStringResourceEx(shell_handle, new_folder_id, MAKELANGID(#LANG_THAI     ,#SUBLANG_DEFAULT) )
    Debug FindStringResourceEx(shell_handle, new_folder_id, MAKELANGID(#LANG_ENGLISH  ,#SUBLANG_DEFAULT) )
    Debug FindStringResourceEx(shell_handle, new_folder_id, MAKELANGID(#LANG_FRENCH   ,#SUBLANG_DEFAULT) )

EndIf
This code is not useful in end-user programs! You can get the "magic numbers" with it
and use them with the LoadString_() method.
It requires some testing (f.e. in a virtual machine) if you get more than 1 magic number.
For example test:
- Win7/Vista English and WinXP Englisch
plus:
- Win7/Vista German/Other and WinXP German/Other

The line:

Code: Select all

new_folder_id = FindResourceStringId(shell_handle, "New Folder", $409); // look for US English "New Folder" resource id.
does not work if english MUI is not installed. It works only with currently installed languages (I tested with German/English/Thai).