Author Topic: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?  (Read 9693 times)

0 Members and 1 Guest are viewing this topic.

Rabbit

  • Guest
I have found several snippets of code relating to file times, particularity dealing with comparing two different file times.  Each one kept failing and I wasn't sure why.  Then after some more research, I find out about the "flaw" with VL-FILE-SYSTIME reporting NIL when a file is marked as being open.  Most times, that would be fine, but what should I do if the file is open and I need to retrieve it's last saved time stamp?  Is there some ARX or VLAX or some other way to access this information?  I don't want to use something that I have to download, like DOS_LIB, to be placed on each machine.

Thanks,
Rabbit

owenwengerd

  • Bull Frog
  • Posts: 451
I don't have any code handy, but you can use the Scripting.FileSystemObject. If you google it, you may find some existing code get the DateLastModified property of a File object.

Lee Mac

  • Seagull
  • Posts: 12905
  • London, England
Perhaps try something like this:

Code - Auto/Visual Lisp: [Select]
  1. (defun _lastmodified ( filename / fnm fso obj rtn )
  2.     (if
  3.         (and
  4.             (setq fnm (findfile filename))
  5.             (setq fso (vlax-create-object "scripting.filesystemobject"))
  6.         )
  7.         (progn
  8.             (setq rtn
  9.                 (vl-catch-all-apply
  10.                     (function
  11.                         (lambda ( )
  12.                             (setq obj (vlax-invoke-method fso 'getfile fnm))
  13.                             (+ 2415019 (vlax-get-property obj 'datelastmodified))
  14.                         )
  15.                     )
  16.                 )
  17.             )
  18.             (if (= 'vla-object (type obj))
  19.                 (vlax-release-object obj)
  20.             )
  21.             (vlax-release-object fso)
  22.             (if (vl-catch-all-error-p rtn)
  23.                 (prompt (vl-catch-all-error-message rtn))
  24.                 rtn
  25.             )
  26.         )
  27.     )
  28. )

Returns Julian date.

Rabbit

  • Guest
Exactly what I was needing Lee.  Yet again, you've surprised me at how you went about what you done.  I was trying to compare the VL-FILE-SYSTIME returns.  With your method, it' comparing REAL's which will return better information.  With that all said, I would've never figured it out.  Looks like you got the information about the file from .NET, C#, C++ or something else that I don't know, nor understand.  As soon as I.T. gets Visual Studio on my computer, I'm diving into C#.  I'm so looking forward to learning it.

I can't say it enough, but "Thanks Again!"
Rabbit

BlackBox

  • King Gator
  • Posts: 3770
Looks like you got the information about the file from .NET, C#, C++ or something else that I don't know, nor understand. 

It's not .NET actually, Visual LISP can tap into the ActiveX COM API (similar to VBA), which is what's happening when one invokes the *Create-Object Methods. In this case Lee's code accesses the FileSystemObject Object.

Like many other Windows Objects, such as Shell.Application, or even the ADsSecurityUtility Object, once you've gotten an active, or created a new instance of (aka an External Object), you can also tap into all of the External Object's Properties, and Methods from LISP (generally speaking)

.NET can also access these Objects, but in a different manor.

Note - Just be sure to safely 'release' External Objects.



As soon as I.T. gets Visual Studio on my computer, I'm diving into C#.  I'm so looking forward to learning it.

You'll enjoy it a lot more after the initial learning curve... This thread may help with that.
"How we think determines what we do, and what we do determines what we get."

pBe

  • Bull Frog
  • Posts: 402
Perhaps try something like this:

Code - Auto/Visual Lisp: [Select]
  1. (defun _lastmodified ( filename / fnm fso obj rtn )
  2. <......>
  3.    

Returns Julian date.

Copy/Paste/Toolbox you go.  :)

You'll enjoy it a lot more after the initial learning curve... This thread may help with that.

<Like:)

BlackBox

  • King Gator
  • Posts: 3770
 :-D

Mark would appreciate your adaptation of the like button. That HarvardX class I mention is pretty awesome too.

/OffTopic
"How we think determines what we do, and what we do determines what we get."

Lee Mac

  • Seagull
  • Posts: 12905
  • London, England
Thank you for providing the explanation Renderman - saved me some time  :-)

You're very welcome Rabbit & pBe, I'm glad it helps.

BlackBox

  • King Gator
  • Posts: 3770
Thank you for providing the explanation Renderman - saved me some time  :-)

Cheers Lee :beer:
"How we think determines what we do, and what we do determines what we get."

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
For the longest time I have been using DOS_LIB's dos_fileex function to deal with vl-file-systime flakiness.

Odd timing: Today I needed to make a DOS_LIB free variant so I penned the code below. For what it's worth ...

Code: [Select]
(defun _Try ( try_statement / try_catch try_result )

    ;;  General purpose error trapper.

    (if
        (vl-catch-all-error-p
            (setq try_catch
                (vl-catch-all-apply
                    (function
                        (lambda ( )
                            (setq try_result (eval try_statement))
                        )
                    )
                )
            )
        )
        (setq *try_errors* ;; lexical global
            (cons
                (list
                    try_statement
                    (vl-catch-all-error-message try_catch)
                )
                *try_errors*
            )
        )
    )

    try_result

)

(defun _JulianToDateStr ( julian_date / @floor @itoa a b c d e f y z year month day hours mins secs )

    ;;  Renamed, reformatted and generally abused version of Jon
    ;;  Fleming's classic JUL_CAL function written around 1991-09-09.
    ;;  This version is coded to return the resulting value as a string,
    ;;  e.g. "20121104_082248". I need this for file creation utilities
    ;;  so often this is the default date format I use. Apologies if this
    ;;  insults your sensibilities. MP.
    ;;  ~ ~ ~
    ;;  Calculate date. It's magic, don't even ask. Some things we
    ;;  weren't meant to know. Jon Fleming.

    (defun @floor ( number )
        (fix
            (if (> number 0)
                number
                (- number 1)
            )
        )
    )

    (defun @itoa ( i / result )
        (setq result (itoa i))
        (while (< (strlen result) 2)
            (setq result (strcat "0" result))
        )
        result
    )

    (setq
        z     (fix julian_date)
        a     (fix (/ (- z 1867216.25) 36524.25))
        a     (+ z 1 a (- (fix (/ a 4))))
        b     (+ a 1524)
        c     (fix (/ (- b 122.1) 365.25))
        d     (@floor (* 365.25 c))
        e     (fix (/ (- b d) 30.6001))
        day   (fix (- b d (@floor (* 30.6001 e))))
        e     (- e (if (< e 14) 2 14))
        month (1+ e)
        year  (if (> e 1) (- c 4716) (- c 4715))
        year  (if (zerop year) (1- year) year)
        ;;    Calculate time. First strip the time portion
        ;;    from the input.
        y     (- julian_date (fix julian_date))
        ;;    Number of hours since midnight.
        hours (fix (* y 24))
        ;;    A temporary variable we'll use a couple of times.
        f     (- y (/ hours 24.0))
        ;;    Number of minutes since midnight (1440 minutes per
        ;;    day).
        mins  (fix (* f 1440))
        ;;    Number of seconds since midnight (86400 seconds per
        ;;    day). MP added (+ 0.5 ...) to match values returned by
        ;;    the vl-file-systime function.
        secs  (fix (+ 0.5 (* (- f (/ mins 1440.0)) 86400)))
    )

    (strcat
        (itoa year) (@itoa month) (@itoa day)
        "_"
        (@itoa hours) (@itoa mins) (@itoa secs)
    )

)

(defun _GetFileDateVL ( filename / path temp result )

    ;;  Return the file's date (last modified) as a string,
    ;;  e.g. "20120911_073435". I need this for file creation
    ;;  utilities so often this is the default date format I
    ;;  use. Apologies if it insults your sensibilities. MP.

    (if (setq path (findfile (findfile filename)))
        (if (_Try '(setq temp (vl-file-systime path)))
            (strcat
                (substr
                    (setq result
                        (apply 'strcat
                            (mapcar
                                (function
                                    (lambda ( n / s )
                                        (if (eq 1 (strlen (setq s (itoa (nth n temp)))))
                                            (strcat "0" s)
                                            s
                                        )
                                    )
                                )
                               '(0 1 3 4 5 6)
                            )
                        )
                    )
                    1 ;; 2014 11 03
                    8
                )
                "_"
                (substr result 9)
            )
        )
    )
)

(defun _FSO ( )

    ;;  cache it (I call it repeatedly)
    (setq *fso* (vlax-create-object "scripting.filesystemobject"))
    (defun _FSO ( ) *fso*)
    *fso*

)

(defun _GetFileDateFSO ( filename / file result )

    ;;  Return the file's date (last modified) as a string,
    ;;  e.g. "20120911_073435". I need this for file creation
    ;;  utilities so often this is the default date format I
    ;;  use. Apologies if it insults your sensibilities. MP.
    ;;
    ;;  Nods to Lee Mac, Black Box, Irneb and Jon Fleming for
    ;;  respective tips, tricks, resources or sample code that
    ;;  contributed to this variant.

    (_Try
       '(setq result
            (_JulianToDateStr
                (+ 2415019
                    (vlax-get
                        (setq file
                            (vlax-invoke
                                (_FSO)
                                'GetFile
                                (findfile filename)
                            )
                        )
                        'DateLastModified
                    )
                )
            )
        )
    )

    (if file (_Try '(vlax-release-object file)))

    result

)

(defun _GetFileDate ( filename / result )

    ;;  Wrapper function for _GetFileDateVL and _GetFileDateFSO
    ;;  functions, visual lisp and file system object methods
    ;;  respectively.
    ;;
    ;;  Return the file's date (last modified) as a string,
    ;;  e.g. "20120911_073435". I need this for file creation
    ;;  utilities so often this is the default date format I
    ;;  use. Apologies if it insults your sensibilities. MP.

    (or
        ;;  try visual lisp first
        (setq result (_GetFileDateVL filename))
        ;;  vl-file-systime failed, call the fso sledge hammer
        (setq result (_GetFileDateFSO filename))
    )

    result

)

tl;dr: _GetFileDate is a wrapper function, will use vl-file-systime based function if it can, otherwise exploiting the file system object based variant. Nods to Lee Mac, Black Box, Irneb and Jon Fleming for respective tips, tricks, resources or sample code that contributed to the variants above.
« Last Edit: November 06, 2014, 10:54:18 AM by MP »
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Cathy

  • Guest
What about using (getvar "tdupdate")? 

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
While it's a worthy suggestion the tdupdate variable is only applicable for the active drawing. I need to be able to (swiftly) determine the date stamp for many files, not just the active drawing, notwithstanding for file types beyond AutoCAD drawings. Cheers. :)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

BlackBox

  • King Gator
  • Posts: 3770
... I need to be able to (swiftly) determine the date stamp for many files, not just the active drawing, notwithstanding for file types beyond AutoCAD drawings. Cheers. :)

[kludge]

Code - Auto/Visual Lisp: [Select]
  1. (defun _FOO (filePath)
  2.   (startapp (strcat "PowerShell -NoExit Get-ChildItem "
  3.                     filePath
  4.                     "| where { $_.LastWriteTime }"
  5.             )
  6.   )
  7.   (princ)
  8. )
  9.  

[/kludge]



[Edit] - For those not already aware, from PowerShell dialog, <Enter> copies selected content to clipboard.

Cheers
"How we think determines what we do, and what we do determines what we get."

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
MANY YEARS LATE BUT ...


Failed to notice this response, thanks BB!
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst