ID:150332
 
Hey there. I'm working on a little saving system (not character saving; it's irrelevant) of files.. I'm trying to see if they already have a savefile made, but it's not recognizing it. I'm using this:
var/F = file("[src].sav") //for seeing if they have file already
if(F) //if they already have a file
world << "found the file"
else
world << "didn't find it"

It always finds it, regardless of one exists or not.

There's probably an easier way to do this, but I couldn't dig it up. Is there another way to see if a file exists? I think it's always returning 1 because I'm just creating a reference, and it obviously exists, but I can't find a workaround.
Vortezz wrote:
Hey there. I'm working on a little saving system (not character saving; it's irrelevant) of files.. I'm trying to see if they already have a savefile made, but it's not recognizing it. I'm using this:
> var/F = file("[src].sav") //for seeing if they have file already
> if(F) //if they already have a file
> world << "found the file"
> else
> world << "didn't find it"
>

It always finds it, regardless of one exists or not.

There's probably an easier way to do this, but I couldn't dig it up. Is there another way to see if a file exists? I think it's always returning 1 because I'm just creating a reference, and it obviously exists, but I can't find a workaround.



Do what I did make a issaved var and after the verb is after the first save set it to one then save that var and run a check for it like so:

var/issaved = 0
//put all your file stuff here
if(issaved>=1)
usr<<"Found it!"
else
usr<<"wasn't found"


And I trust you know how to Read and Write single vars.
If I didn't make it clear enough in this post you can tell me and I will explain a little better. This way of doing it worked pretty well in my save system to check if the player already had a savefile or not.
In response to Nadrew
Nadrew wrote:
Do what I did make a issaved var and after the verb is after the first save set it to one then save that var and run a check for it like so:

Hmm. I know there's a way to actually see if one exists without any vars. Using an issaved var will be my last resort.
There's probably an easier way to do this, but I couldn't dig it up. Is there another way to see if a file exists? I think it's always returning 1 because I'm just creating a reference, and it obviously exists, but I can't find a workaround.

Yep, I think you're right. This was an interesting problem and not quite as straightforward as it seems. It would be nice if Dantom could provide a fexists() proc to handle this for us - I imagine it would get used a fair amount. Any last minute chance of that?

Anyway, I did finally work out a solution. Two actually, but one of them could possibly fail if the file is large. Here's the one that I guarantee to work (well, technically there is one instance where it could fail if you're running a BYOND server under UNIX):
proc/basename(path)
var/slash = 0
var/cslash = 0
do
slash = cslash
cslash = findtext(path, "/", slash+1)
if (!cslash)
cslash = findtext(path, "\\", slash+1)
while (cslash)
if (slash)
return copytext(path, slash+1)
else
return path

mob
verb/fexists(f as text)
var/fl[] = flist(f)
var/bn = basename(f)
for (var/file in fl)
if (cmptext(file, bn))
src << "The file [f] exists!"
return
else if (cmptext(file, "[bn]/") || cmptext(file, "[bn]\\"))
src << "The file [f] is actually a directory!"
return
src << "The file [f] does not exist"

It would actually be much easier if you know that the file to be checked will always be in the current directory (you wouldn't need any of that basename() crap). It would fail under UNIX if you give it a filename like "blah\blahblah" (with a backslash) and a file called "blahblah" existed. Unfortunately I don't think there is an easy way to determine what operating system you're running on (feature request #2?) so there's not much that can be done about this. But it doesn't apply to you and I'm rambling!

Anyway, the other method should not be used but I'll put it here just for fun. Again, don't use this - it would take a long time on a large file and could fail if that file is bigger than the amount of disk space left on the server.
mob
verb/fexists_bad_bad_bad(f as text)
var/randnum = rand(1, 10000)
var/randomfile = "random-[randnum].tmp"
if (fcopy(f, randomfile))
src << "File [f] exists!"
fdel(randomfile)
else
src << "[f] doesn't exist"

Any questions?

Oh, final feature request related to this - the basename() proc could be simplified if there were an rfindtext() proc available. Should be simple enough to slip in if you feel like it, right?

Finally... bug report. The "\\" stuff was giving me fits because the code syntax highlighting interprets the \" as an escaped quote rather than the escaped backslash. Thus anything on the line after that is colored as a quoted string even though it's not. It compiled and ran fine but I didn't even try compiling for a little bit because I thought it wouldn't work.
In response to Air Mapster
Hmm.. that didn't work.. I didn't need the basename() stuff.

Maybe I'll just wait it out and maybe Dantom'll make a fexist() proc =P. If not, I'll work your method around a bit. :-)

Thanks, Air!
In response to Air Mapster
Air Mapster wrote:
Yep, I think you're right. This was an interesting problem and not quite as straightforward as it seems. It would be nice if Dantom could provide a fexists() proc to handle this for us - I imagine it would get used a fair amount. Any last minute chance of that?
proc/fexists(path)
var/list/L = flist(path)
return (L.len>0)

Oh, final feature request related to this - the basename() proc could be simplified if there were an rfindtext() proc available. Should be simple enough to slip in if you feel like it, right?

A soft-coded solution should suffice:
proc/rfindtext(haystack,needle)
for(var/i=length(haystack),i>0,i--)
if(copytext(haystack,i,i+length(needle))==needle) return i
return 0

The text stuff isn't really super efficient as is, so I think the extra overhead will be negligeable.

Finally... bug report. The "\\" stuff was giving me fits because the code syntax highlighting interprets the \" as an escaped quote rather than the escaped backslash.

Yep, good call. By complete coincidence, Zilal stumbled upon this a few days ago and I fixed it then.
In response to Tom
Tom wrote:
> proc/fexists(path)
> var/list/L = flist(path)
> return (L.len>0)
>

Nope. flist() returns a "list of files contained in the specified directory and whose names begin with the specified text." That means if I have a file called byond.dm and I call fexists("b"), it will return true even if a file called b does not exist. Thus I have to check to see if any element of the returned list is exactly equal to the path specified. Furthermore, if the path is not in the current directory, I have to extract the basename out of that path in order to do the checking because flist() only returns the basenames, not the full paths of matching files. As I said, the problem was not as straightforward as it might seem.

However, the implementation internal to BYOND would be very simple, should you choose to accept your mission. It's trivial in C:
#include <stdio.h>

main(int argc, char **argv) {
FILE *f;
if (argc > 1) {
f = fopen(argv[1], "r");
if (f != NULL) {
printf("File %s exists\n", argv[1]);
fclose(f);
} else {
printf("File %s does not exist\n", argv[1]);
}
}
}

Not sure why my method wasn't working for Vortezz though, works perfectly for me.

A soft-coded solution should suffice:
> proc/rfindtext(haystack,needle)
> for(var/i=length(haystack),i>0,i--)
> if(copytext(haystack,i,i+length(needle))==needle) return i
> return 0
>

The text stuff isn't really super efficient as is, so I think the extra overhead will be negligeable.

Good call, I'm sure that's more efficient than what I did.
In response to Air Mapster
Air Mapster wrote:
Nope. flist() returns a "list of files contained in the specified directory and whose names begin with the specified text." That means if I have a file called byond.dm and I call fexists("b"), it will return true even if a file called b does not exist.

Oops. Ok, let's try another approach:
proc/fexist(path)
var/F = file(path)
return length(F)!=null


if (f != NULL) {
printf("File %s exists\n", argv[1]);
fclose(f);
} else {

Ick. Your Mapist brace style is a disgrace to coding purists everywhere.
In response to Tom
Ick. Your Mapist brace style is a disgrace to coding purists everywhere.

Well, my style is more or less like this:

if (yadda != yiddy) {
//yadda yadda
}
else {
//yiddy yiddy
}

I think that's Danist, right?