Reading line X from a file
#1

Two questions:

If I have a file with 50 lines, and I want to know how many lines there are, apart from looping through them or storing the number of lines somewhere (perhaps in the file itself), what can I do?

If I want to read line 15 from the file, what do I do?

I've been looking on the wiki and in file.inc itself but it doesn't seem to have these capabilities? I thought perhaps fseek() could be used for this, but that only works for individual characters - not lines.



EDIT: Well, I've made this:

pawn Code:
stock ReadFileRandomLine(filename[], dest[], dest_size)
{
    new File:file = fopen(filename, io_read);

    new str[256], lines;
    while(fread(file, str)) lines++;
    new line = random(lines);
    fseek(file, 0);
    for(new i=0; i<line; i++) fread(file, str);
   
    format(dest, dest_size, "%s", str);
    strdel(dest, strlen(dest)-1, strlen(dest));

    fclose(file);
    return 1;
}
But I'm still wondering if there's a better way! I had to do strdel() because this weird thing happened where there would be a new line after the string.

This could need to be called 100+ times in a single moment, so efficiency matters here.

I benchmarked this with 100 iterations (the maximum that will ever be needed at one moment) with this line repeated 100 times in a file: '1234.5678, 1234.5678, 1234.5678, 180.0' and it took 600 MS. Not TOO bad I guess, but still I'd like to make this more efficient. I guess using format() isn't a great idea, but I'm not sure how else to do the string. Perhaps returning the string would be better.
Reply
#2

Well, i dont think there is a better way than what u did here
just a little hint: u can do
pawn Code:
dest[strlen(dest)-1] = 0;
instead of strdel (faster)

EDIT: use "strmid" instead of format
Code:
strmid(dest, src, 0, strlen(src)-1);
Reply
#3

Okay, I changed format() to just returning the string and it cut the time in HALF.

Now. I have a new problem. Not really a scripting issue, more of a design issue. Let me explain:

The files are going to contain spawnpoints, for example:

scriptfiles/spawns/food/cluck/cluck_ls.txt
scriptfiles/spawns/food/cluck/cluck_sf.txt
scriptfiles/spawns/food/cluck/cluck_lv.txt

scriptfiles/spawns/police/lspd.txt
scriptfiles/spawns/police/sfpd.txt
scriptfiles/spawns/police/lvpd.txt

etc.

I don't want totally random spawns though, as players will end up spawning inside each other. I'm not sure how to get around this though. I've been thinking about various different ideas, such as 'watching' each spawnpoint and when the player that spawned there has moved away it becomes 'free'. But if I have 10 spawnpoints for cops at the LSPD and there are 11 cops online, what happens to the 11th person, who will be spawning at the exact same time as the other 10 cops?


I'm now totally re-thinking my spawn system. Here's my idea:

When you register you'll spawn at a pre-set place (as this idea was going towards) but there will be one per class. If you're a cop in LS, you spawn in front of the LSPD.

When you die, you respawn at a hospital.

When you join the server again, you respawn where you left off, in the vehicle you were in (if any).

When the city transitions, you also respawn where you started off. This one is the problem. There are 3 cities but not really 3 lives. The 'previous coordinates' won't exist if you only just registered then the city changes. I don't want players respawning in LS when the city changes to SF. Perhaps again just the 'initial spawns' could be used. It's just that maybe 20 people will have registered in the 168 minutes the server was in LS, then they're all going to be spawning at the same place..
Reply
#4

i've made that quickly, but should work properly.

PHP Code:
stock GetLine(file[] , line dest[] , size sizeof dest// in both errors, the passed string will be null;
{
    new 
File:f_file fopen(file,io_read);
    if( ( !
f_file || line ) && fclose(f_file) ) return 0// When a file fails to open, it's closed.
    
for(new i_lines fread(f_file,dest,size) ; i_lines++)
    {
        if(
line == i_lines)
        {
            
fclose(f_file);
            return 
1;
        }
    }
    
fclose(f_file);
    return -
1;
}
// here it's an example of its usage.
switch(GetLine(file[],line,dest))
{
     case -
1:
     {
          print(
"line doesn't exist");
     }
     case 
0:
     {
          print(
"couldn't handle the file or the line is invalid");
     }
     case 
1:
     {
          print(
dest);
     }

For solving your second issue, about the player spawn. You should save in the players files, in which city they was in their last logins.
Reply
#5

@leonardo1434:
Your GetLine function, on numerous occasions, leaves the file handle open. This can be a bad practice or result in memory staying allocated after a server crash (I don't think the PAWN api takes care of closing it).

Anyways, I don't think this is exactly what MP2 is looking for, either.

@OP:
If raw performance is what you're seeking, don't be afraid to "integrate" this function with your code natively. This will save you a function call, but more importantly, will help you get rid of the elements of the function that are not necessary for you (for example the check of whether the line parameter is higher than 0 - in 99% cases you already KNOW it is, unless it is user-input you're handling).
If you want more specific code advice on how to get the top notch speed out of your code, you're going to need to post some.
Reply
#6

@leonardo1434: i think he needs some function to return a random line from a file
yours returns an already known line

@MP2: i think i might have a better optimized code here:
pawn Code:
stock ReadFileRandomLine(filename[])
{
    new File:file = fopen(filename, io_read);

    while(fread(file, str))
    {
        if(random(3) == 1)
        {
            fclose(file);
            src[strlen(src) - 1] = 0;
            return src;
        }
    }
    fclose(file);
    src[strlen(src) - 1] = 0;
    return src;
}
Now, this will loop through all the file lines (by reading them), then gets a random value between 0 - 2
if the random value is 1 then it'll return the last readed line, so in short u'll have a chance on three every iteration (u can increase it in random call)
Reply
#7

Quote:
Originally Posted by AndreT
View Post
@leonardo1434:
Your GetLine function, on numerous occasions, leaves the file handle open. This can be a bad practice or result in memory staying allocated after a server crash (I don't think the PAWN api takes care of closing it).

Anyways, I don't think this is exactly what MP2 is looking for, either.

@OP:
If raw performance is what you're seeking, don't be afraid to "integrate" this function with your code natively. This will save you a function call, but more importantly, will help you get rid of the elements of the function that are not necessary for you (for example the check of whether the line parameter is higher than 0 - in 99% cases you already KNOW it is, unless it is user-input you're handling).
If you want more specific code advice on how to get the top notch speed out of your code, you're going to need to post some.
Thanks ! i didn't noticed, but it's fixed now.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)