Operations with Files and Directories



FILE-COPY: "from_filename" "to_filename"

This word copies a specified file. If the target directory already contains the file with specified name, the old file will be overwritten (unless it is used by another application ). If you don't change the filename when copying a file, then it would be sufficient to specify the receiving directory (without filename) in the argument to_filename.
This command does not support operations with file masks and it cannot be used to delete a directory. To process several files, use FOR-FILES: loop.

Examples:

FILE-COPY: "c:\xxx\test.txt" "c:\xxx\new.txt"
FILE-COPY: "c:\xxx\test.txt" "d:\backup\another_test.txt" 
\ copying file  test.txt to directory  c:\yyy\
FILE-COPY: "c:\xxx\test.txt" "c:\yyy\"
\ copying file  test.txt to file  backup
FILE-COPY: "c:\xxx\test.txt" "c:\backup"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" from_filename" S" to_filename" FCOPY

FILE-MOVE: "from_filename" "to_filename"

This word moves a specified file. If you don't change the filename when moving a file, then it would be sufficient to specify the receiving directory (without filename) in the argument to_filename.
This command does not support operations with file masks and it cannot be used to delete a directory. To process several files, use FOR-FILES: loop.

Examples:

FILE-MOVE: "c:\xxx\test.txt" "c:\xxx\new.txt"
FILE-MOVE: "c:\xxx\test.txt" "d:\backup\test.txt"
\ moving file  test.txt to directory  c:\yyy\
FILE-MOVE: "c:\xxx\test.txt" "c:\yyy\"
\ moving file  test.txt to file  backup
FILE-MOVE: "c:\xxx\test.txt" "c:\backup"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" from_filename" S" to_filename" FMOVE

FILE-RENAME: "old_filename" "new_filename"

Renames a specified file. If you use this word just to move a file without changing its filename, then it would be sufficient to specify the receiving directory (without filename) in the argument to_filename. Unlike "FILE-MOVE:" word, this command can rename (move) directories, but only within the same drive.

Examples:

FILE-RENAME: "c:\xxx\test.txt" "c:\xxx\new.txt"
FILE-RENAME: "c:\xxx" "c:\yyy" \ only within the same drive 
\ moving file  test.txt to directory  c:\yyy\
FILE-RENAME: "c:\xxx\test.txt" "c:\yyy\"
\ renaming file  test.txt to  backup
FILE-RENAME: "c:\xxx\test.txt" "c:\backup"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" old_filename" S" new_filename" FRENAME

FILE-SIZE: "file_pattern"

Returns the size of a specified file (double number). To get the aggregate size of all files in a directory use the word DIR-SIZE:.

Examples:

\ checking file size and displaying a message
10240. FILE-SIZE: "c:\test.txt" D<
IF MSG: "File size exceeds 10kb"
ELSE MSG: "File size less then 10kb"
THEN
#( test_file_size
\ the action will be executed if the file size exceeds 10 kb
Rule: 10240. FILE-SIZE: "c:\test.txt" D<
Action:
    \ ... performing some useful actions
)# 

#( test_file_size1
\ displaying a message if a specified file 
\ is greater than 100kb
NoActive
Action:
    102400. FILE-SIZE: "c:\fido\sessions.log" D<
    IF
        MSG: "File size exceeds 100 kb!"
    THEN
)#

#( test_delete_empty
\ recursively deleting from a specified folder
\ all the files whose size equals  0 NoActive
 Action:
     RECURSIVE
     FOR-FILES: "c:\xxx\*.*"
         0. FILE-SIZE: "%FOUND-FULLPATH%" D=
         IF FILE-DELETE: "%FOUND-FULLPATH%" THEN
     ;FOR-FILES
)#

There also exists a postfix version of this word:

S" filename" FSIZE


FILE-DELETE: "filename"

Deletes a specified file. Supports masks of filenames. If you want to delete all files matching a specified mask not just in main directory, but in all its subdirectories as well, use modifier RECURSIVE before word FILE-DELETE:

This word cannot be used to delete a directory. If you want to delete a directory rather then a file, use DIR-DELETE.

Example:

FILE-DELETE: "c:\xxx\test.txt"
FILE-DELETE: "c:\xxx\*.txt"
RECURSIVE FILE-DELETE: "c:\xxx\*.txt"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" filename" FDELETE

You shouldn't use with this word the standard method of getting an error code (GetLastError), because FILE-DELETE: works with masks and always returns error #18 (There are no more files. ERROR_NO_MORE_FILES).

However, if you want to get an error code after deleting a file, you can use a standard Forth word DELETE-FILE ( c-addr u -- ior )

Example:

S" myfile.txt" DELETE-FILE ?DUP IF ." Error # " . CR THEN

FILE-EMPTY: "file_pattern"

Returns TRUE (-1) if a file is empty or if it doesn't exist.


FILE-EXIST: "file_pattern"

Returns TRUE (-1) if a specified file or directory exists.

There also exists a postfix version of this word:

S" file_pattern" EXIST?

FILE-CREATE: "filename"

Creates an empty new file with a specified name. Creates all the intermediate directories if necessary. If you want to create a directory rather then a file, use DIR-CREATE:.

Examples:

\ creates an empty file named  'test.txt' in the root directory of C: drive
FILE-CREATE: "c:\test.txt"
\ creates an empty file named  'test.txt' in  'c:\xxx\yyy\zzz'
\ all the  intermediate directories which do not exist will be created.
FILE-CREATE: "c:\xxx\yyy\zzz\test.txt" 

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" filename" FCREATE


FILE-WRITE: "filename" "text"

Writes content of argument "text" into a specified file, removing the file's previous content.

It is possible to use user-defined variables and nnCron's predefined variables in arguments of word FILE-WRITE. To write into a file quotation mark character and per cent sign character, use variables %QUOTE% and %PERCENT% respectively. You can use variable %FILE: filename% to write to a file content of another file.

Examples:

FILE-WRITE: "c:\xxx\test.txt" "Last update: %hh%:%mm%"
FILE-WRITE: "c:\xxx\test.txt" "%USERNAME% was there!" 
FILE-WRITE: "c:\xxx\test.txt" "Content of another file:%crlf%%crlf%%FILE: c:\yyy\source.txt%"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" filename" S" text" FWRITE


FILE-APPEND: "filename" "text"

This word is similar to FILE-WRITE:, but it does not overwrite the target file's content, but appends the new information in the end of file.

Examples:

FILE-APPEND: "c:\xxx\test.txt" "Message was sent at: %hh%:%mm%%crlf%"
FILE-APPEND: "c:\xxx\test.txt" "Content of another file:%crlf%%FILE: c:\yyy\source.txt%"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word (FAPPEND):

S" text" S" filename" FAPPEND


DIR-CREATE: "path"

Creates a specified directory and, if necessary, all the intermediate directories.

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.


DIR-DELETE: "path"

Deletes a specified directory or a directory tree.
Use with care: a specified catalog or a tree will be deleted even if they are not empty.

Example:

DIR-DELETE: "c:\xxx"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.


DIR-SIZE: "path"

Returns the aggregate size of all files in a directory (a double number).

Example:

#( test_dir_size
\ displaying a message if aggregate size of files 
\ in directory  c:\cpp exceeds 100kb (without subdirectories)
NoActive
Action:
    102400. DIR-SIZE: "c:\cpp" D<
    IF
        MSG: "Dir size exceeds 100 kb!"
    THEN
)#

In order to find out a size of a directory including all the subdirectories, place modifier RECURSIVE before DIR-SIZE:.

Example:

#( test_dir_size1
\ displaying a message if aggregate size in directory 'c:\cpp'
\ exceeds 100kb (including files in all  subdirectories)
NoActive
Action:
    102400. RECURSIVE DIR-SIZE: "c:\cpp" D<
    IF
        MSG: "Dir size exceeds 100 kb!"
    THEN
)#

There also exists a postfix version of this word:

S" dirname" DIR-SIZE


DIR-EMPTY: "path"

Returns "TRUE" if a specified directory is empty and "FALSE" if it contains at least on file or subdirectory.
Please note that DIR-EMPTY returns "TRUE" even if a specified directory does not exist.


ONLYDIR

Receives a string with full file path and file name (S" fullpath" ONLYDIR) and returns a string, containing file path only (without a file name). For example, when receiving a string 'd:\tools\nnbackup\nnbackup.exe', this word will return 'd:\tools\nnbackup'.

Attention please: you can use this word when defining a task, but you can not use it in console!

Example:

#( test_filename
NoActive
Action:
    FILESONLY 
    FOR-FILES: "C:\TEMP\*"
        MSG: "Full filename: %FOUND-FULLPATH%%crlf%\
Path only: %FOUND-FULLPATH ONLYDIR%"
;FOR-FILES )#

See also: ONLYNAME


ONLYNAME

Receives a string with full file path and file name (S" fullpath" ONLYNAME) and returns a string, containing file name only (without a file path). For example, when receiving a string 'd:\tools\nnbackup\nnbackup.exe', this word will return 'nnbackup.exe'.

Attention please: you can use this word when defining a task, but you can not use it in console!

Example:

#( test_filename1
NoActive
Action:
    FILESONLY 
    FOR-FILES: "C:\TEMP\*"
        MSG: "Full filename: %FOUND-FULLPATH%%crlf%\
Name only: %FOUND-FULLPATH ONLYNAME%"
;FOR-FILES )#

See also: ONLYDIR


FOR-FILES: "path\mask" <...> ;FOR-FILES

This word can be used to perform operations not just on single files, but entire groups of files matching a specified filename mask; commands included in the body of FOR-FILES loop will be applied to each of these files.

Example:

#( test_for_files
\ removing all the files with  "*.txt" extension in directory  "c:\xxx"
NoActive
Action:
    FOR-FILES: "c:\xxx\*.txt"
        FILE-DELETE: "%FOUND-FULLPATH%"
    ;FOR-FILES
)#

It works in this way: if there are five files matching a certain mask, then FOR-FILES: loop will be automatically executed five times and each time values of the following variables will be renewed:

%FOUND-FILENAME% name of a file matching the search pattern (e.g. test.txt)
%FOUND-FULLPATH% full path and name of file matching the search pattern (e.g. 'c:\xxx\yyy\test.txt')
%FOUND-RELPATH% path and name of file matching the search pattern, relative to the directory where search is performed (e.g. 'yyy\test.txt')

That means that on each iteration of the loop you get access to the name of the next file matching a specified mask, and now it only remains to perform the required action with this file (i.e. remove, move or rename it etc.) or to perform another check in order to decide what to do with this particular file.

Here is the list of checks which can be performed in the body of FOR-FILES: loop (use word "0=", to reverse the condition):

IS-DIR? Returns 'TRUE' if a directory is found
IS-HIDDEN? Returns 'TRUE' if a file/directory with attribute hidden is found
IS-READONLY? Returns 'TRUE' if a file/directory with attribute read-only is found'
IS-SYSTEM?
Returns 'TRUE' if a file/directory with attribute system is found
IS-ARCHIVE? Returns 'TRUE' if a file/directory with attribute hidden is found'

Example:

\ all the file and subdirectories inside the directory "c:\xxx" match the pattern used here,
\ but due to additional checks, we will only  process subdirectories 
\ and  files with attributes "hidden" and "read-only"
FOR-FILES: "c:\xxx\*"
    \ checking if the found file is a directory
    IS-DIR?
    IF
        \ ... commands for performing operations with directories, including those with  "hidden" and "read-only" attributes
    ELSE
\ checking if the found file has attribute "hidden" IS-HIDDEN? IF \ ... commands for performing operations with hidden files ELSE \ checking if the found file has attribute "read-only" IS-READONLY? IF \ ... commands for performing operations with read-only files THEN THEN THEN ;FOR-FILES

Besides, the body of FOR-FILES: loop can contain instructions for performing operations with dates of file creation and modification and last access (take a look at "Working with Dates and Time"):

CREATION-DATE Date of creation of a found file
ACCESS-DATE Date of last access to found file
WRITE-DATE Date when a found file was written
CUR-DATE System date
DATE- Difference between two dates ( date1-date2 ). Returns the difference between two dates in days.

Example:

#( test_for_files1
\ removes from directory "c:\xxx" all files 
\ created more than ten days ago
NoActive
Action:
    FOR-FILES: "c:\xxx\*"
        \ working only with files, ruling directories out 
        IS-DIR? 0=
IF CUR-DATE CREATION-DATE DATE- 10 > IF FILE-DELETE: "%FOUND-FULLPATH%" THEN THEN ;FOR-FILES )#

The following modifiers can be used before FOR-FILES:

RECURSIVE

Working with a specified directory and all its subdirectories
TODEPTH Searching the "deep levels" of a directory tree.

There are two ways to perform a search in a directory tree:
1. First a current (upper-level) directory is processed, and after that all the subdirectories
(this method is used by default).
2. First all the subdirectories are searched, and then the current directory.
To do this, one should use TODEPTH.

FILESONLY

Instructions in the body of FOR-FILES: are performed on files only, and not on directories.

SKIPERRORS

Ignore file access errors when moving through a directory tree

Examples:

#( test_for_files2
\ removing all the files and directories in directory "c:\xxx".
\ word FILE-DELETE: deletes files,
\ and word DIR-DELETE: deletes directories 
NoActive
Action:
    RECURSIVE
    FOR-FILES: "c:\xxx\*"
        \ checking if the found file is a directory
        IS-DIR?
        IF
            DIR-DELETE: "%FOUND-FULLPATH%"
        ELSE 
            FILE-DELETE: "%FOUND-FULLPATH%"
        THEN
    ;FOR-FILES
)#
#( test_for_files3 \ deleting all files with zero length from directory c:\zzz and all its subdirectories \ deleting files only, but not the directories. NoActive Action: RECURSIVE FILESONLY FOR-FILES: "c:\zzz\*.*" FILE-SIZE: "%FOUND-FULLPATH%" D0= IF FILE-DELETE: "%FOUND-FULLPATH%" THEN ;FOR-FILES )#

If necessary, you can always exit FOR-FILES: loop by using word FF-EXIT.

Example:

#( test_for_files4
\ displays messages with names of all 
\ text files in directory C:\TEMP\
\ exits the loop when file exit.txt is found
NoActive
Action:
    FOR-FILES: "C:\TEMP\*.txt"
        MSG: "%FOUND-FILENAME%"
        \ matching name of each found file against name "exit.txt"
        RE-MATCH: "%FOUND-FILENAME%" "/exit.txt/i"
        \ if name is the same, leaving the loop
        IF FF-EXIT THEN
    ;FOR-FILES
    BEEP: 250 500
)#

FILE-CROP: "filename" <max_size> <size_after_crop>

Permits to control size of text files. Removes beginning of a specified file so that its size does not exceed the value of size_after_crop. File will be cropped only if its size is greater than the value of max_size.

Values of max_size size_after_crop are in kilobytes.

This word is used mostly to control size of log files.

Example:

\ log file  sessions.log will be cropped down to  500 kb 
\ if it was greater than 1000 kb when FILE-CROP was called
FILE-CROP: "c:\fido\sessions.log" 1000 500
\ log file  nncron.log will be cropped down to  50 kb 
\ if it was greater than 100 kb when FILE-CROP was called
FILE-CROP: "log\nncron.log" 100 50

There also exists a postfix version of this word:

S" filename" <max_size> <size_after_crop> FCROPkb


PURGE-OLD: "path\mask" <days>
PURGE-OLDW: "path\mask" <days>
PURGE-OLDA: "path\mask" <days>

These words remove all the files which match a specified mask and are older then a specified number of days. PURGE-OLD: checks the file creation date, PURGE-OLDW: checks the date when a file was last written into and PURGE-OLDA: checks the date when a file was last accessed.

Use modifier RECURSIVE to delete all files in the specified directory and all its subdirectories.

If value of days is set to -1, then all files will be deleted from a directory.

Examples:

\ deleting all files more than 3 days old from Windows Temp directory
PURGE-OLD: "c:\windows\temp\*" 3
\ deleting from the specified directory and all its subdirectories all text files
\ which were last written into more that 10 days ago
RECURSIVE
PURGE-OLDW: "c:\drafts\*.txt" 10
\ removing all files from Windows Temp directory
PURGE-OLD: "c:\windows\temp\*" -1

By default, words of PURGE-OLD*: group remove only files, but by using modifier WITHDIRS, you can delete both files an directories older than a specified number of days. Please be careful when using it: directories older than a specified period of time will be deleted with all their content!

Example:

\ removing ALL files and directories
WITHDIRS 
PURGE-OLD: "c:\windows\temp\*" -1

There also exists a postfix version of these words:

S" c:\temp\*.txt" -1 PURGE-OLD
S" c:\temp\*" 10 PURGE-OLDW
WITHDIRS S" c:\temp\test\*.bat" 5 PURGE-OLDA

FILE-CREATION-DATE: "path" (you can also use word FILE-DATE: "path")
FILE-ACCESS-DATE: "path"
FILE-WRITE-DATE: "path"

These words return numeric values of date of creation of a file, date of last access and date when the file was last modified (these values are resented in a special binary DATE-format). These three words can be used to perform operations with these three types of dates.

Current system time can be placed on stack with the help of word CUR-DATE. Word DATE- returns the difference (in days) between 2 dates. Methods of handling dates and of their conversion between different formats are described in chapter Working with Dates and Time.

Examples:

#( test_file_date
\ removing file new.txt if it was created more than 30 days ago
NoActive
Action:
    CUR-DATE
    FILE-CREATION-DATE: "c:\xxx\new.txt"
    DATE- 30 > 
    IF
        FILE-DELETE: "c:\xxx\new.txt"
    THEN
)# 

There also exists a postfix version of these words:

S" filename" FCDATE
S" filename" FADATE
S" filename" FWDATE

See also: