Best way to create a temporary unique file-name?

Posted by OctavioOlguin on 28-Nov-2015 12:32

Greettinigs.

Making appserver app, I need to create temporary file for one process.  So I realized that if that process is run by several clients at the "same" time, I need to get a unique temporary file-name for each.

What would be best practices at this?

Is it practical to name the file as a GUID?  Is it portable across file systems?

something like USER-ID("database") + string(etime)?

I wonder what could we determine as best practices.

thanks for your input.

All Replies

Posted by Mike Fechner on 28-Nov-2015 12:38

A GUID should be o.k.

When using a session-managed AppServer (e.g. state-less) you can also use the SESSION:SERVER-CONNECTION-ID property on the AppServer. This is unique per client - useful when the different client requests are handled by different agent processes over time.

Posted by OctavioOlguin on 28-Nov-2015 13:32

Thanks Mike.

I missed to say that I'm using state-free :(

Posted by Jeff Ledbetter on 29-Nov-2015 09:30

This is our getTempPathname function. It's not the most glorious code in the world, but it works. I'm sure using a GUID as the basename is more much elegant but this was written before that.

RETURNS CHARACTER
  ( INPUT Pdir AS CHARACTER,
    INPUT Pext AS CHARACTER ) :
/*------------------------------------------------------------------------------
  Purpose:  Generate a scratch file pathname with specified directory and
            extension.
    Notes:  
------------------------------------------------------------------------------*/
  DEFINE VARIABLE Mbasename AS CHARACTER   NO-UNDO.
  DEFINE VARIABLE Merror    AS CHARACTER   NO-UNDO.
  DEFINE VARIABLE Mfilename AS CHARACTER   NO-UNDO.
  DEFINE VARIABLE Mpathname AS CHARACTER   NO-UNDO.

  /*
   In the unlikely event that we generate an existing pathname, we
   loop until we have a non-existent pathname.

   (Shamelessly borrowed from adecomm/ _tmpfile.p)
  */
  DO WHILE TRUE:
    ASSIGN 
      /* Start with 8-digit basename */
      Mbasename = STRING(RANDOM(0,9999),"9999")
                  + STRING((TIME * 100 + ETIME) MODULO 10000,"9999")

      /* Append extention, if specified */
      Mfilename = Mbasename + (IF Pext <> "" THEN "." + Pext ELSE "")

      /* Prefix with directory, if specified */
      Mpathname = (IF Pdir <> "" THEN
                          REPLACE(Pdir,"~\","~/")
                          + (IF SUBSTRING(Pdir,LENGTH(Pdir),1) = "/"
                                OR SUBSTRING(Pdir,LENGTH(Pdir),1) = "~\" THEN
                               ""
                             ELSE
                               "/")
                        ELSE
                          "")
                       + Mfilename.

    /* If the file doesn't exist, then leave the loop */
    IF SEARCH(Mpathname) = ? THEN LEAVE.
  END.

  IF Pdir <> "" THEN DO:
    Merror = DYNAMIC-FUNCTION('fnRtbMakeOSPath':U,Mpathname).
    IF Merror <> "" THEN Mpathname = ?.
  END.

  RETURN Mpathname.

END FUNCTION.

Posted by olivier.dunemann on 30-Nov-2015 02:28

If you are wandering in the wonderful world of Microsoft, the System.IO.Path:GetTempFileName() method should help you too.

https://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename%28v=vs.110%29.aspx


[Code]
DEF VAR cFileName AS CHAR NO-UNDO.

cFileName = System.IO.Path:GetTempFileName().

MESSAGE cFileName

   VIEW-AS ALERT-BOX INFO BUTTONS OK.

OS-DELETE VALUE(cFileName).
[/Code]

Posted by Mike Fechner on 30-Nov-2015 02:34

The OP was asking for the AppServer. Using .NET on the AppServer limits platform compatibility.

.NET on the classic AppServer is only supported from OE11 on.

Plus PASOE in 11.5 does not support .NET

Posted by Patrick Tingen on 30-Nov-2015 05:37

We used a similar approach as Jeff mentioned, but at one point I had to investigate why it took up to 20 seconds to determine a 'free' file name. It turned out that files were not properly cleaned up when the process ended, so the temp-folder was full of temp files and most numbers were already used. So it had to iterate literally thousands of time before it could find a free number.

I changed it to include both date and time in the temp name. * And * to clean up at the end of the process :)

Posted by OctavioOlguin on 01-Dec-2015 09:56

Indeed, very enlightening....

I learned lot whit this, not just how to get the filename, but also on the consecuences  of choices....

thanks all!!!

Posted by OctavioOlguin on 01-Dec-2015 10:00

after all,

can we conclude that

cTempFile = REPLACE(UUID, "-", "").

makes a safe temp file name? it's portable and trusty ?

Greetings

Posted by Peter Judge on 01-Dec-2015 10:11

You can also call adecomm/_tmpfile.p  which is always available in $DLC.

File: _tmpfile.p

Description:

Creates an available temp file name. The name is a complete

name that includes the path.

Input Parameters:

user_chars:   Characters that can be used to distinguish a temp

file from another temp file in the same application.

extension:    The file extension that is to be added to the file,

including the "."

Output Parameters:

name:         The name of the file

Posted by OctavioOlguin on 11-Dec-2017 19:51

Re-programming the original progam that springed this question, I came to realize that using ENTRY(5, GUID, "-") makes a good option, also, as some 3 to 4 seconds the file is erased,

(reprogrammed as more experience on my side and government changes, urged to revisit the program)

redo procedural as OO...

Posted by tbergman on 11-Dec-2017 20:20

If you’re on Windows, try
System.IO.Path:GetTempFileName()
 

Posted by OctavioOlguin on 12-Dec-2017 08:46

Thanks... but it will be used on PASOE, so at the moment will test guids options...

Thanks!!!

This thread is closed