Raised This Month: $28 Target: $400
 7% 

Using Files to write data/values(old and new file commands)


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
schnitzelmaker
Senior Member
Join Date: Apr 2006
Location: HERE
Old 10-21-2006 , 13:47   Using Files to write data/values(old and new file commands)
Reply With Quote #1

This is a little tutorial about reading/writing files to store something.
This Tutorial need basics in Amxx Scripting.
I am not so good in explain and writing Tutorials,so the most are writing as code.
I dont explain every Command.
If there something wrong or better please post.


Lets begin with the old file commands (easy and short).

Code:
read_file ( const file[], line, text[], len, &txtLen )
Read a specific line with given lenght into an array.
It returns index of next line or 0 when the end of the file is reached.
The number of characters read is stored in txtLen.
Code:
write_file ( const file[], const text[], [ line ] )
Write an array to file to the given line,if line is -1 it write at end of the file

Code:
#include <amxmodx> #include <amxmisc> #define PLUGIN "Filehandle" #define VERSION "1.0" #define AUTHOR "Administrator" new filename[256] public plugin_init() {     register_plugin(PLUGIN, VERSION, AUTHOR)         /*get the config directory of amxx*/     get_configsdir(filename,255)     format(filename,255,"%s/filehandle.txt",filename)     register_concmd("amx_filetestwrite","filewritetest")     register_concmd("amx_filetestread","filereadtest") } public filewritetest(id){     new writedata[128]     new steamid[32],name[32],anyvalue,Float:anyfloatvalue         /*Lets create and copy some dummy data*/     get_user_authid(id,steamid,31)     get_user_name(id,name,31)     anyvalue = 10     anyfloatvalue = 5.5         formatex(writedata,127,"%s %s %d %f",steamid,name,anyvalue,anyfloatvalue)         /*Now write this data to the file at last line     write_file ( const file[], const text[], [ line ] )     The line parameter defaults to -1, which appends to the end of the file. Otherwise, a specific line is overwritten.     If no file exist write_file create one*/     write_file(filename,writedata) } public filereadtest(id){     new readdata[128],steamid[32],anyvalue,Float:anyfloatvalue,txtlen     new parsedsteamid[32],parsedname[32],parsedanyvalue[8],parsedanyfloatvalue[8]         /*now read the data from the file*/     /*It give 2 ways to read a file until end of line*/         /*The first way*/     /*file_size - Returns the size of a file.     If flag is 0, size is returned in bytes.     If flag is 1, the number of lines is returned.     If flag is 2, 1 is returned if the file ends in a line feed.     If the file doesn't exist, -1 is returned. */     new fsize = file_size(filename,1)     for (new line=0;line<=fsize;line++)     {         /*read_file ( const file[], line, text[], len, &txtLen )*/         read_file(filename,line,readdata,127,txtlen)         /*We must parse the readata in somthing that we can use*/         parse(readdata,parsedsteamid,31,parsedname,31,parsedanyvalue,7,parsedanyfloatvalue,7)                 /*check if steamid the same as in file*/         get_user_authid(id,steamid,31)         if(equal(steamid,parsedsteamid))         {             /*steamid is same as in file,the do somthing with the rest of parsed values*/             anyvalue = str_to_num(parsedanyvalue)             anyfloatvalue = str_to_float(parsedanyfloatvalue)             client_print(id,print_chat,"Your saved Steamid:%s Name:%s Value:%d FloatValue:%f",parsedsteamid,parsedname,anyvalue,anyfloatvalue)             /*i use break to stop the loop to save more performance.On big files this is good*/             break             //...         }     }         /*The second way/the better way*/     new line = 0     while(!read_file(filename,line++,readdata,127,txtlen))     {         parse(filename,parsedsteamid,31,parsedname,31,parsedanyvalue,7,parsedanyfloatvalue,7)                 get_user_authid(id,steamid,31)         if(equal(steamid,parsedsteamid))         {             anyvalue = str_to_num(parsedanyvalue)             anyfloatvalue = str_to_float(parsedanyfloatvalue)             client_print(id,print_chat,"Your saved Steamid:%s Name:%s Value:%d FloatValue:%f",parsedsteamid,parsedname,anyvalue,anyfloatvalue)             break             //...         }     }    }

The next are the new file commands(many and very powerfull)

Lets begin with basics of new file commands and write/read a string inside a file.
This is good for textfiles where easily can read the file

The new file commands dont read linespecific,they use a cursor inside the file to read the data.
This cursor position can get with
Code:
ftell(file)
And the cursor can set with
Code:
fseek ( file, position, start )
"position" is an offset from start
start can be:
Code:
SEEK_SET //beginning of the file
SEEK_CUR //current cursor position
SEEK_END //end of the file
Code:
rewind ( file )
move the cursor position to begin of the file.

Code:
fopen ( filename[], mode[] )
Open a file with given filename and mode.
It returns a pointer to the file.

Code:
fputs ( file, const text[])
Write a string to a text file at current filecursor position.
"file" must be a pointer to a file from the fopen command.
Code:
fprintf ( file, const buffer[], ... )
Write a formated string to a text file.Same as the format/formatex command,but for files.

fputs/fprint dont add a newline at end of the string,so it must set manually.
Code:
fgets ( file, buffer[], maxlength )
Read a line (including newlines) from a text file from current filecursor position until maxlenght is reached or newline/end of file is founded.
Code:
#include <amxmodx> #include <amxmisc> #define PLUGIN "Filehandle" #define VERSION "1.0" #define AUTHOR "Administrator" new filename[256] public plugin_init() {     register_plugin(PLUGIN, VERSION, AUTHOR)         get_configsdir(filename,255)     format(filename,255,"%s/filehandle.txt",filename)     register_concmd("amx_filetestwrite","filewritetest")     register_concmd("amx_filetestread","filereadtest") } public filewritetest(id){     new writedata[128]     new steamid[32],name[32],anyvalue,Float:anyfloatvalue         get_user_authid(id,steamid,31)     get_user_name(id,name,31)     anyvalue = 10     anyfloatvalue = 5.5         /*fopen - Returns a file handle for advanced file functions.     Mode uses the standard C library of mode types.     The first character can be:     "a" - append     "r" - read     "w" - write         The second character can be:     "t" - text     "b" - binary         You can also append a "+" to specify both read and write.     Open a file in append+read+write mode     On mode "a+"/"w+" it create a file if there no exist     Mode "w+" overwrite a file if one exist*/     new filepointer = fopen(filename,"a+")     /*check if file is open,on an error filepointer is 0*/     if(filepointer)     {         /*It give 2 ways to write a string inside a file*/                 /*First way*/         formatex(writedata,127,"%s %s %d %f^n",steamid,name,anyvalue,anyfloatvalue)         //The new file commands need to create a newline manual with "^n"                 /*write the string to the file*/         /*another commands are:         fputc - Writes a char (1 byte) to a file handle.         fputf - Writes a float (4 bytes, 8 on AMD64) to a file handle.         fputi - Writes an integer (4 bytes) to a file handle.         fputl - Writes a long (4 bytes) to a file handle. */         fputs(filepointer,writedata)                 /*Second way*/         /*fprintf - Writes a line to a file */         fprintf(filepointer,"%s %s %d %f^n",steamid,name,anyvalue,anyfloatvalue)                 /*close the file,this is optional,but better is it to close the file*/         fclose(filepointer)     } } public filereadtest(id){     /*open file in read-mode*/     new filepointer = fopen(filename,"r")     /*check if file is open,on an error filepointer is 0*/     if(filepointer)     {         new readdata[128],steamid[32],anyvalue,Float:anyfloatvalue         new parsedsteamid[32],parsedname[32],parsedanyvalue[8],parsedanyfloatvalue[8]             /*Read the file until it is at end of file*/         /*fgets - Reads a line from a text file -- includes newline!*/         while(fgets(filepointer,readdata,127))         {                parse(readdata,parsedsteamid,31,parsedname,31,parsedanyvalue,7,parsedanyfloatvalue,7)                     get_user_authid(id,steamid,31)             if(equal(steamid,parsedsteamid))             {                 anyvalue = str_to_num(parsedanyvalue)                 anyfloatvalue = str_to_float(parsedanyfloatvalue)                 client_print(id,print_chat,"Your saved Steamid:%s Name:%s Value:%d FloatValue:%f",parsedsteamid,parsedname,anyvalue,anyfloatvalue)                 break                 //...             }         }         fclose(filepointer)     } }

To write a file where must save many data ,the plugin growing big and are many work to write with using Parse,str_to_,...
Here a little trick that i have learn to use strucs in Pawn.
This is very easy to manage the filedata and adding new data,but every change need to change/convert also the file.


Code:
enum enumname{}
enum give the variable inside the {} a number.It begin with number 0.
With "new variablename[enumname]" it create a variable with the arraylenght of the given enum.
Code:
fwrite_raw ( file, const stream[], blocksize, mode )
Write an array to the file at current cursor position."blocksize" is the size of the array or the lenght who want to write.
Mode can be:
Code:
BLOCK_INT //Good to write any value/char
BLOCK_SHORT //For writing values -32767 -> 32767 and chars
BLOCK_CHAR //Good for writing chars/values -127 -> 127
BLOCK_BYTE //Same as char
Code:
fread_raw ( file, stream[], blocksize, blocknum )
Reads blocknum blocks from a file at current file cursor position until blocksize is reached or end of the file is found.It returns the number of succesfully readed blocks.

Code:
#include <amxmodx> #include <amxmisc> #define PLUGIN "Filehandle" #define VERSION "1.0" #define AUTHOR "Administrator" new filename[256] enum PLAYER_DATABASE {     STEAMID[32],     NAME[32],     ANYVALUE,     ANYFLOATVALUE,         PLAYER_DATABASE_END } new player_data[33][PLAYER_DATABASE] public plugin_init() {     register_plugin(PLUGIN, VERSION, AUTHOR)         get_configsdir(filename,255)     format(filename,255,"%s/filehandle.txt",filename)     register_concmd("amx_filetestwrite","filewritetest")     register_concmd("amx_filetestread","filereadtest") } public filewritetest(id){     /*Lets create and copy some dummy data into data*/     get_user_authid(id,player_data[id][STEAMID],31)     get_user_name(id,player_data[id][NAME],31)     player_data[id][ANYVALUE] = 10     /*theres a little problem with enum and floats:player_data[id][ANYFLOATVALUE] = 5.5 return an tag mismatch error     this error can be ignored but a better way is using _: in front of the float value*/     player_data[id][ANYFLOATVALUE] = _:5.5         new fp=fopen(filename,"a+")     if(fp)     {         /*There exist 3 commands         fwrite - Writes an element to a file (for single chars)         fwrite_blocks - Writes a block of data in a file (for unknown,havent get any good results with this)         fwrite_raw - Writes blocks of data to a file (for strings/arrays)*/         fwrite_raw(fp,player_data[id][PLAYER_DATABASE:0],sizeof(player_data[]),BLOCK_INT)         /*Now i explain the fwrite_raw         fp is the filepointer         player_data[id] is the data from player         [PLAYER_DATABASE:0] is the begining of the data who want to write,         to write only Steamid it need to use player_data[id][PLAYER_DATABASE:STEAMID]         sizeof(player_data[]) is the lenght of data which want to write,         to write somthing like only steamid it need "player_data[id][PLAYER_DATABASE:STEAMID],32"         */     }     fclose(fp)  } public filereadtest(id){     new readdata[PLAYER_DATABASE],steamid[32]     new fp=fopen(filename,"r")     if(fp)     {         while(fread_raw(fp,readdata[PLAYER_DATABASE:0],sizeof(player_data[]),1))         {                get_user_authid(id,steamid,31)             if(equal(steamid,readdata[STEAMID]))             {                 player_data[id][ANYVALUE] = readdata[ANYVALUE]                 player_data[id][ANYFLOATVALUE] = _:readdata[ANYFLOATVALUE]                 copy(player_data[id][STEAMID],31,readdata[STEAMID])                 copy(player_data[id][NAME],31,readdata[NAME])                 client_print(id,print_chat,"Your saved Steamid:%s Name:%s Value:%d FloatValue:%f",readdata[STEAMID],readdata[NAME],readdata[ANYVALUE],readdata[ANYFLOATVALUE])                 client_print(id,print_chat,"Your saved Data:%s Name:%s Value:%d FloatValue:%f",player_data[id][STEAMID],player_data[id][NAME],player_data[id][ANYVALUE],player_data[id][ANYFLOATVALUE])                 break                 //...             }         }     }     fclose(fp) }

I hope i can help some with this little tutorial.
At the end i add the final Plugin that can be used as core to write/read data from file.
Attached Files
File Type: sma Get Plugin or Get Source (Filehandle.sma - 1643 views - 2.4 KB)
__________________

Last edited by schnitzelmaker; 10-21-2006 at 16:47.
schnitzelmaker is offline
Old 10-21-2006, 14:11
Zenith77
This message has been deleted by Brad. Reason: mostly spam. don't.
Bad_Bud
Senior Member
Join Date: Oct 2006
Location: The internet
Old 10-22-2006 , 15:25   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #2

Nice tutorial.

Anyway, I have a question for you.

I'm writing a plugin that tries to update some lines in files with new text... I was trying to just use appending to the file, but it seems like whenever append is used, it adds a new line... let me try to explain what I'm trying to do a bit better:

There is a string (containing spaces) of an unknown length saved to a text file. I would like to allow the user to type in a phrase (not of a limited length), such as "likes blue cars." so that I can add it to the unknown string on the unknown string's line.

So it would read in the unknown, which might be "Bad Bud ", add in the new string "likes blue cars." with format, so the final string would read "Bad Bud likes blue cars.", and save it back to its original line in the text file (overwriting "Bad Bud " with "Bad Bud likes blue cars.").

How can I do this? I've tried, but it keeps adding weird characters to the end of the added string. They look like this: o>‘|b>‘|

Any suggestions? Sorry for crappily explaining my problem.
Bad_Bud is offline
Old 10-22-2006, 16:28
schnitzelmaker
This message has been deleted by schnitzelmaker.
Bad_Bud
Senior Member
Join Date: Oct 2006
Location: The internet
Old 10-22-2006 , 19:53   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #3

Both of the strings are unknown. One is saved from previous user input, and the new one is saved from user input, all I need to do is combine them. It doesn't really matter what the values are, I just used those phrases as examples for what the user might have typed in. Is it not possible to just read a line until you reach the end of the line then stop? What I was doing was pseudo working, because it was reading the text from the file, but it was adding those weird end of string and backslash characters and I'm not sure how to get rid of them.

If you want to see my code as an example, I can send it to you. I just don't want everyone getting access to it because it's something new and cool and needs more stuff to make it work in its entirety.
Bad_Bud is offline
Old 10-23-2006, 08:07
schnitzelmaker
This message has been deleted by schnitzelmaker.
Bad_Bud
Senior Member
Join Date: Oct 2006
Location: The internet
Old 10-23-2006 , 15:12   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #4

I was trying to use the old file system for reading specific lines, because that's how they're written to the file. I'll send you the pm. Each time it reads a line it seems to bring in that other junk at the end.
Bad_Bud is offline
jopmako
Senior Member
Join Date: Jul 2006
Location: QQ:331537639
Old 10-23-2006 , 15:56   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #5

yeah,I'll try this
thx
__________________
QQ31537639
jopmako is offline
Send a message via MSN to jopmako
Bad_Bud
Senior Member
Join Date: Oct 2006
Location: The internet
Old 10-24-2006 , 18:56   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #6

Hmm... I had a small bug. It no longer prints those random characters anymore. I'll still send you the code when I'm done, if you're interested.
Bad_Bud is offline
Old 10-25-2006, 01:33
schnitzelmaker
This message has been deleted by schnitzelmaker.
Bad_Bud
Senior Member
Join Date: Oct 2006
Location: The internet
Old 10-25-2006 , 21:40   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #7

Sorry, it's still kinda buggy, so I'm not done yet. So many exceptions I need to take care of to make it work...
Bad_Bud is offline
teame06
i have a hat
Join Date: Feb 2005
Location: Hat City
Old 10-26-2006 , 17:54   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #8

Here some info you might want to add.. When using fgets it will read the full line including the new line marker.. ^n

http://wiki.amxmodx.org/index.php/AM...t_File_Natives
__________________
No private support via Instant Message
GunGame:SM Released
teame06 is offline
Send a message via AIM to teame06
The Specialist
BANNED
Join Date: Nov 2006
Old 12-10-2006 , 19:21   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #9

I have a question. Im saving origins to a file , And I want to load them all into a menu how would i do this with the new read wrtie commands?
The Specialist is offline
Send a message via AIM to The Specialist
schnitzelmaker
Senior Member
Join Date: Apr 2006
Location: HERE
Old 12-11-2006 , 13:27   Re: Using Files to write data/values(old and new file commands)
Reply With Quote #10

Based on your plugin in another help thread i have make the example for it.

WARNING:This example read ONLY 1 line,if you want read more you need a for or while loop.

I have make 2 plugins,how you can use it,but i prior the second.
I have add some things and have comments some out,which can be removed or uncomment.
Both plugins are tested and work,but are not optimized.

Code:
#include <amxmodx> #include <amxmisc> #include <fakemeta> new g_Switch; //new g_TransportAccess; new filename[256]; /*------------------------------------------------------------------------------------------------*/ enum ORIGIN_DATA {  ADMIN_ID[32],  MAP_NAME[32],  Float:ORIGIN[3],    END_DATA } new MSP_Data[33][ORIGIN_DATA]; /*------------------------------------------------------------------------------------------------*/ public plugin_init() {  register_plugin("Multi-Server Portal","0.1","The Specialist");  g_Switch = register_cvar("msp_switch","1");  //g_TransportAccess = register_cvar("msp_jump_access","0");  get_configsdir(filename,255);  format(filename,255,"%s/msp_origins.txt",filename);  register_concmd("msp_create_jump","create_jump_point",ADMIN_LEVEL_A,"Creates An Origin For Portal Where Admin Is");  //register_concmd("msp_add_server","add_server",ADMIN_LEVEL_A,"Adds A Server To The List By IP");  register_clcmd("say /menu","showmenu")     } /*------------------------------------------------------------------------------------------------*/ public showmenu(id){     new menuBody[512],Float:origin[3]         new fp = fopen(filename,"r")         if (fp)     {         fread_raw(fp,MSP_Data[id][ORIGIN_DATA:0],sizeof(MSP_Data[]),1)                 //you can use to copy to another variable(as example here "Float:origin[3]") or use it direct(see in the formatex)         origin[0] = MSP_Data[id][ORIGIN][0]         origin[1] = MSP_Data[id][ORIGIN][1]         origin[2] = MSP_Data[id][ORIGIN][2]                 formatex(menuBody, 511, "This show your origins %f,%f,%f ,%f,%f,%f",origin[0],origin[1],origin[2],MSP_Data[id][ORIGIN][0],MSP_Data[id][ORIGIN][1],MSP_Data[id][ORIGIN][2])         fclose(fp)     }     else formatex(menuBody, 511, "Oh an error with filename: %s",filename)     show_menu(id, MENU_KEY_0, menuBody) } public create_jump_point(id,level,cid) {  if(cmd_access(id , level , cid , 0) && get_pcvar_num(g_Switch))  {   pev(id,pev_origin,MSP_Data[id][ORIGIN]);   get_mapname(MSP_Data[id][MAP_NAME],31);   get_user_authid(id,MSP_Data[id][ADMIN_ID],31);     new FP = fopen(filename,"a+");     if( FP)   {    fwrite_raw(FP,MSP_Data[id][ORIGIN_DATA:0],sizeof(MSP_Data[]),BLOCK_INT)    fclose(FP);    client_print(id,print_chat,"Done")    return 0;   }  }  return 1; }

The second way:
Code:
#include <amxmodx> #include <amxmisc> #include <fakemeta> new g_Switch; //new g_TransportAccess; new filename[256]; /*------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------*/ public plugin_init() {  register_plugin("Multi-Server Portal","0.1","The Specialist");  g_Switch = register_cvar("msp_switch","1");  //g_TransportAccess = register_cvar("msp_jump_access","0");  get_configsdir(filename,255);  format(filename,255,"%s/msp_origins.txt",filename);  register_concmd("msp_create_jump","create_jump_point",ADMIN_LEVEL_A,"Creates An Origin For Portal Where Admin Is");  //register_concmd("msp_add_server","add_server",ADMIN_LEVEL_A,"Adds A Server To The List By IP");  register_clcmd("say /menu","showmenu")     } /*------------------------------------------------------------------------------------------------*/ public showmenu(id){     new menuBody[512],Float:origin[3],origin0[16],origin1[16],origin2[16]         new fp = fopen(filename,"r")         if (fp)     {         fgets(fp,menuBody,511)//I use menuBody,so i not need a second array                 parse(menuBody,origin0,15,origin1,15,origin2,15)         origin[0] = str_to_float(origin0)         origin[1] = str_to_float(origin1)         origin[2] = str_to_float(origin2)                 formatex(menuBody, 511, "This show your origins %f,%f,%f",origin[0],origin[1],origin[2])         fclose(fp)     }     else formatex(menuBody, 511, "Oh an error with filename: %s",filename)     show_menu(id, MENU_KEY_0, menuBody)     } public create_jump_point(id,level,cid) {  if(cmd_access(id , level , cid , 0) && get_pcvar_num(g_Switch))  {   new Float:origin[3],Mapname[32],Authid[32]   pev(id,pev_origin,origin);   get_mapname(Mapname,31);   get_user_authid(id,Authid,31);     new FP = fopen(filename,"a+");     if( FP)   {    fprintf(FP,"%f %f %f %s %s^n",origin[0],origin[1],origin[2],Mapname,Authid)    fclose(FP);    client_print(id,print_chat,"Done")    return 0;   }  }  return 1; }
__________________

Last edited by schnitzelmaker; 12-11-2006 at 13:33.
schnitzelmaker is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 16:57.


Powered by vBulletin®
Copyright ©2000 - 2021, vBulletin Solutions, Inc.
Theme made by Freecode