File handling

All except GUI problems
Post Reply
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

File handling

Post by Robert »

Hi

I always assumed that if I wrote:

Code: Select all

  loc  :=  Files.dir.This ("D:\Data\ProjectX");
for example, and the path did not exist, that I would get loc = NIL.

However that does not seem to be the case.

What is the easiest way to test if a specific path exists?

Thanks

Robert
User avatar
Ivan Denisov
Posts: 362
Joined: Tue Sep 17, 2013 12:21 am
Location: Krasnoyarsk, Russia

Re: File handling

Post by Ivan Denisov »

You can use Files.dir.LocList for that.

Example

Code: Select all

MODULE PrivTest;

	IMPORT  Log, Files;
	
	PROCEDURE Do*;
		VAR info: Files.LocInfo;
	BEGIN
		info  :=  Files.dir.LocList(Files.dir.This ("D:\Data\ProjectX"));
		IF info = NIL THEN
			Log.String("No such folder"); Log.Ln
		ELSE
			WHILE info.next # NIL DO
				Log.String(info.name); Log.Ln;
				info := info.next
			END
		END
	END Do;

END PrivTest.
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: File handling

Post by Robert »

Ivan

Thanks for the suggestion, but I don't think it works!

The "No such folder" string does not tell me that the stated folder does not exist, but rather that it has no sub-folders.


I know how to solve the problem (ie parse the folder string to strip off the last level, then call LocList, then scan the list for the stripped off bottom level).

The purpose of my question was to know if there is a simpler way.


Sorry for long (over two years) time to reply. I guess that this is not my most important problem!

Cheers,
Robert
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: File handling

Post by Robert »

I tried another simple approach to check if a directory path exists:

Code: Select all

loc  :=  Files.dir.This ("D:\Data\ProjectX");
IF loc.res = 0 ...
because the Files Docu says that loc.res = 2 means "location or file not found".

This does not work either!
In fact in all my experiments loc is always non-NIL, and loc.res always equals 0 - "no error".

This makes me suspect that procedures such as StdDialog.GetSubLoc are buggy, as they seem to rely on loc = NIL for missing directories?

Robert

PS - I have just remembered that I solved this problem (years ago).
Call PathFileExistsW from shlwapi.dll:

Code: Select all

MODULE  CasketShlwapiDll ["shlwapi.dll"];
IMPORT  SYSTEM, Win := WinApi;
PROCEDURE  PathFileExistsW* (path : Win.PtrWSTR) : Win.BOOL;
END  CasketShlwapiDll.
with wrapper

Code: Select all

PROCEDURE  PathExists* (path : ARRAY OF CHAR) : BOOLEAN;
  VAR
    k, m  :  INTEGER;
    chr   :  CHAR;
  BEGIN
    k  :=  0; m  :=  -1;
    REPEAT
      chr  :=  path [k];
      IF  (chr = '/')  OR  (chr = '\')  THEN  m  :=  k  END;
      INC (k);
    UNTIL  chr  =  0X;
    path [m]  :=  0X;
    RETURN  Shlwapi.PathFileExistsW (path)  =  WinApi.TRUE
  END  PathExists;
manumart1
Posts: 67
Joined: Tue Sep 17, 2013 6:25 am

Re: File handling

Post by manumart1 »

You need to test the existence of a folder.
If you know that that folder will ALWAYS have a known file, then you can test for the existence of that file. If file does not exist, then folder does not exist.

For example, the file can be readme.txt, and have a content like this:
This file must be named "readme.txt" and must be in folder "C:\abc\def".
It is necessary for the proper functioning of the application.

Code: Select all

  VAR fLoc: Files.Locator; f: Files.File;

  fLoc := Files.dir.This("C:\abc\def"); 
  f := Files.dir.Old(fLoc, "readme.txt", Files.shared);
  IF fLoc.res # 0 THEN
    Error. Folder does not exist
  ELSE
    f.Close();
  END;
My answer is just an indirect way of knowing if a folder exists, and need to impose an obligation to the folder: to store a well known file.

Regards
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: File handling

Post by Robert »

I think there are several problems with the solution I posted. My latest suggestion is

Code: Select all

MODULE  CasketShlwapiDll ["shlwapi.dll"];
IMPORT  SYSTEM, Win := WinApi;
PROCEDURE  PathIsDirectoryW* (path : Win.PtrWSTR) : Win.BOOL;
END  CasketShlwapiDll.
with a 'wrapper'

Code: Select all

PROCEDURE  TrimTail (VAR path : ARRAY OF CHAR);
  VAR
    k, m  :  INTEGER;
    chr   :  CHAR;
  BEGIN
    k  :=  0; m  :=  -1;
    REPEAT
      chr  :=  path [k];
      IF  (chr = '/')  OR  (chr = '\')  THEN  m  :=  k  END;
      INC (k)
    UNTIL  chr  =  0X;
    path [m + 1]  :=  0X    
  END  TrimTail;

PROCEDURE  IsDirectory* (path : ARRAY OF CHAR; trimTail : BOOLEAN) : BOOLEAN;
  BEGIN
    IF  trimTail  THEN  TrimTail (path)  END;
    RETURN  Shlwapi.PathIsDirectoryW (path)  #  WinApi.FALSE
  END  IsDirectory;
The option trimTail allows you to pass a full filename, and it will ignore the file part of the full path by cutting out anything after the last '/' or '\'.

This kind of file manipulation seems to be very difficult in BlackBox, but I seem to remember it was always difficult in every language I have ever used!

Cheers,
Robert
manumart1
Posts: 67
Joined: Tue Sep 17, 2013 6:25 am

Re: File handling

Post by manumart1 »

Your procedure TrimTrail is similar to HostFiles.GetPath, that is not exported.

Code: Select all

MODULE HostFiles;
...
PROCEDURE GetPath (IN fname: FullName; OUT path: FullName);
	VAR i: INTEGER;
BEGIN
	path := fname$; i := LEN(path$);
	WHILE (i > 0) & (path[i] # "\") & (path[i] # "/") & (path[i-1] # ":") DO DEC(i) END;
	path[i] := 0X
END GetPath;
Josef Templ
Posts: 262
Joined: Tue Sep 17, 2013 6:50 am

Re: File handling

Post by Josef Templ »

It may make sense indeed to add two functions "IsFile" and "IsDir" to Files.Locator.
They would return TRUE if and only if the locator exists and represents a file resp. a directory.
Similar functions are also available in Java, for example.

- Josef
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: File handling

Post by Robert »

Josef Templ wrote:It may make sense indeed to add two functions ...
I have a list of 5 that I think are of general utility and I find difficult in standard BlackBox.

Whether they should be associated with Locators, or Module Files, or a non-standard BlackBox library in Cpc for example is a different discussion.

Their interfaces are

Code: Select all

PROCEDURE CopyFile (IN srcName, dstName: ARRAY OF CHAR; buildPath, allowOverwrite: BOOLEAN): BOOLEAN;
PROCEDURE CreateDirectory (IN path: ARRAY OF CHAR): BOOLEAN;
PROCEDURE CreatePath (IN path: ARRAY OF CHAR; trimTail: BOOLEAN; OUT cnt: INTEGER);
PROCEDURE IsDirectory (path: ARRAY OF CHAR; trimTail: BOOLEAN): BOOLEAN;
PROCEDURE PathFileExists (name: ARRAY OF CHAR; trimTail: BOOLEAN): BOOLEAN;
If anyone is interested I can send them the full Docu & Mod files.

Regards
Robert
Post Reply