Raised This Month: $51 Target: $400
 12% 

Edit a word inside a text file


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
aron9forever
Veteran Member
Join Date: Feb 2013
Location: Rromania
Old 05-16-2015 , 19:07   Edit a word inside a text file
Reply With Quote #1

I've been struggling for the past hour, but with no use. I just can't understand how files work in amxx. Maybe because I'm tired.

Anyways, suppose we have a file inside amxmodx/configs/messages.txt
and the contents of messages.txt are
PHP Code:
What a nice day
Problems
Good night 
I want to change "Problems" into "No problems" then rewrite the file.

How would I do this? I tried reading the whole file as a string then using replace_all and I failed miserably.
Code snips would also be very welcome
__________________
Meanwhile, in 2050:
Quote:
Originally Posted by aron9forever
useless small optimizations
Quote:
Originally Posted by Black Rose View Post
On a map that is 512x512x128 units you end up with 3,355,443,200,000 different "positions". To store each one of those positions individually in the variable "user_or" you need 12 terabytes of memory.
aron9forever is offline
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 05-16-2015 , 22:58   Re: Edit a word inside a text file
Reply With Quote #2

Read the file. Change the appropriate words. Write to the file (make sure to overwrite original contents).

Quote:
Originally Posted by aron9forever View Post
I failed miserably.
What does that mean?

Quote:
Originally Posted by aron9forever View Post
Code snips would also be very welcome
Quid pro quo. You basically just said "do this for me".
__________________

Last edited by fysiks; 05-16-2015 at 23:00.
fysiks is offline
HamletEagle
AMX Mod X Plugin Approver
Join Date: Sep 2013
Location: Romania
Old 05-17-2015 , 04:08   Re: Edit a word inside a text file
Reply With Quote #3

You can take a look inside BombStatus plugin, it has the feature to remove specific line from file. You can adapt that and work with it.

If you are too lazy:
PHP Code:

public plugin_init()
{
    
ChangeLine("Problems""No Problems")
}

stock ChangeLine(const OldLine[], const NewLine[])
{
    new const 
FileName[] = "file_testing.ini"
    
new const TempFileName[] = "tempfile.ini"

    
new ConfigDirPath[128]; get_configsdir(ConfigDirPathcharsmax(ConfigDirPath))
    new 
FullPath[256]; formatex(FullPathcharsmax(FullPath), "%s/%s"ConfigDirPathFileName)

    new 
FilePointer fopen(FullPath"rt")
    if(
FilePointer)
    {
        new 
TempFilePath[256]; formatex(TempFilePathcharsmax(TempFilePath), "%s/%s"ConfigDirPathTempFileName)
        
        new 
InputFilePointer fopen(TempFilePath"wt")
        if(
InputFilePointer)
        {
            new 
FileData[128]
            while(!
feof(FilePointer))
            {
                
fgets(FilePointerFileDatacharsmax(FileData))
                
trim(FileData)
                
                if(
equal(FileDataOldLine))
                {
                    
copy(FileDatacharsmax(FileData), NewLine)
                }
                
fprintf(InputFilePointer"%s^n"FileData)
            }
            
            
fclose(InputFilePointer)
            
fclose(FilePointer)

            
delete_file(FullPath)
            
rename_file(TempFilePathFullPath1)
            
            return 
1
        
}
    }
    return 
0

Note that this is just an example, to show you how it could be done. Further things depend on how you will use it(if you are going to call it many times, it would be good to cache all changes that needs to be done inside an array and do it during plugin_end and adjust the string on the fly).
__________________

Last edited by HamletEagle; 05-17-2015 at 05:24.
HamletEagle is offline
aron9forever
Veteran Member
Join Date: Feb 2013
Location: Rromania
Old 05-17-2015 , 09:01   Re: Edit a word inside a text file
Reply With Quote #4

here's how I tried to do it. @Hamlet, I need to change a word not a whole line, but I will make it work with your way
It's only called once so no need to cache stuff
PHP Code:
new filepointer fopen("addons/amxmodx/configs/hello.txt","r+")
        
/*check if file is open,on an error filepointer is 0*/
        
if(filepointer)
        {
            new 
readdata[512]
            
/*Read the file until it is at end of file*/
            
while(fgets(filepointer,readdata,511))
            {   
                
replace_all(readdata511"Problems""No problems")
            }
            
fputs(filepointer,readdata)
            
fclose(filepointer)
        } 
I understand how files, pointers and cursor works in PHP, but I couldn't even read the whole file in a string, so I'll try what you posted now
__________________
Meanwhile, in 2050:
Quote:
Originally Posted by aron9forever
useless small optimizations
Quote:
Originally Posted by Black Rose View Post
On a map that is 512x512x128 units you end up with 3,355,443,200,000 different "positions". To store each one of those positions individually in the variable "user_or" you need 12 terabytes of memory.
aron9forever is offline
HamletEagle
AMX Mod X Plugin Approver
Join Date: Sep 2013
Location: Romania
Old 05-17-2015 , 09:38   Re: Edit a word inside a text file
Reply With Quote #5

Then:
PHP Code:
stock ChangeWord(const OldWord[], const NewWord[])
{
    new const 
FileName[] = "file_testing.ini"
    
new const TempFileName[] = "tempfile.ini"

    
new ConfigDirPath[128]; get_configsdir(ConfigDirPathcharsmax(ConfigDirPath))
    new 
FullPath[256]; formatex(FullPathcharsmax(FullPath), "%s/%s"ConfigDirPathFileName)

    new 
FilePointer fopen(FullPath"rt")
    if(
FilePointer)
    {
        new 
TempFilePath[256]; formatex(TempFilePathcharsmax(TempFilePath), "%s/%s"ConfigDirPathTempFileName)
        
        new 
InputFilePointer fopen(TempFilePath"wt")
        if(
InputFilePointer)
        {
            new 
FileData[128]
            while(!
feof(FilePointer))
            {
                
fgets(FilePointerFileDatacharsmax(FileData))
                
trim(FileData)
                
                if(
contain(FileDataOldWord) != -1)
                {
                    
replace(FileDatacharsmax(FileData), OldWordNewWord)
                }
                
fprintf(InputFilePointer"%s^n"FileData)
            }
            
            
fclose(InputFilePointer)
            
fclose(FilePointer)

            
delete_file(FullPath)
            
rename_file(TempFilePathFullPath1)
            
            return 
1
        
}
    }
    return 
0

Change the give word everytime it occurs.
__________________
HamletEagle is offline
aron9forever
Veteran Member
Join Date: Feb 2013
Location: Rromania
Old 05-17-2015 , 09:50   Re: Edit a word inside a text file
Reply With Quote #6

I get how it works now. You're reading line by line, then checking the lines, then writing line by line on a new file.
Isn't it possible to read the entire file into memory then rewrite the original file? (asking out of curiosity, this method is just fine)
__________________
Meanwhile, in 2050:
Quote:
Originally Posted by aron9forever
useless small optimizations
Quote:
Originally Posted by Black Rose View Post
On a map that is 512x512x128 units you end up with 3,355,443,200,000 different "positions". To store each one of those positions individually in the variable "user_or" you need 12 terabytes of memory.
aron9forever is offline
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 05-17-2015 , 13:18   Re: Edit a word inside a text file
Reply With Quote #7

Have you tried LoadFileForMe()?
__________________
fysiks is offline
Bugsy
AMX Mod X Moderator
Join Date: Feb 2005
Location: NJ, USA
Old 05-23-2015 , 10:49   Re: Edit a word inside a text file
Reply With Quote #8

This will replace every instance of szFind with szReplaceWith in a file. Keep in mind that this reads the file in DATA_BUFFER_SIZE chunks and if szFind is located between chunks then it will not get replaced. Easiest way to avoid this is to size DATA_BUFFER_SIZE larger than the file, or use a method that reads 1 line at a time. If you're using 1.8.3+, use replace_string() instead of replace_all().

Edit: Updated it to handle szReplaceWith[] that is larger than szFind[]. If szReplaceWith is larger, it will use half of the data buffer for reading file data, and the other half to allow for the extra characters in szReplaceWith. If szReplaceWith is <= szFind, it will use the full buffer for reading file data. If OP can give more details about the potential size of this file, I can probably tweak it to be more reliable. If all else fails, a line-by-line replacer may be better.

PHP Code:
ReplaceTextInFile"my_file.txt" "find this" "replace with this" );
//Returns 1 on success, 0 on fail. 
PHP Code:
ReplaceTextInFile( const szFile[] , const szFind[] , const szReplaceWith[] )
{
    const 
DATA_BUFFER_SIZE 1024;
    
    new 
iSrcFile iDestFile szDestFile64 ] , szBufferDATA_BUFFER_SIZE ] , iLen iBytesRead iMaxBytesToRead;
    
    
formatexszDestFile charsmaxszDestFile ) , "%s_tmp" szFile );
    
    if ( ( 
iSrcFile fopenszFile "r" ) ) && ( iDestFile fopenszDestFile "w+" ) ) )
    {
        
iMaxBytesToRead = ( strlenszReplaceWith ) > strlenszFind ) ) ? ( DATA_BUFFER_SIZE ) : charsmaxszBuffer );
        
        while ( ( 
iBytesRead fread_blocksiSrcFile szBuffer iMaxBytesToRead BLOCK_CHAR ) ) )
        {
            
szBufferiBytesRead ] = EOS;
        
            
replace_allszBuffer charsmaxszBuffer ) , szFind szReplaceWith );
            
iLen strlenszBuffer );

            
fwrite_blocksiDestFile szBuffer iLen BLOCK_CHAR );
        }
        
        
fcloseiSrcFile );
        
fcloseiDestFile );
    }
    
    return ( 
iSrcFile && iDestFile && delete_fileszFile ) && rename_fileszDestFile szFile ) );

__________________

Last edited by Bugsy; 05-24-2015 at 00:32.
Bugsy is offline
Old 05-23-2015, 17:15
.Dare Devil.
This message has been deleted by .Dare Devil.. Reason: nonsense
Bugsy
AMX Mod X Moderator
Join Date: Feb 2005
Location: NJ, USA
Old 05-23-2015 , 18:49   Re: Edit a word inside a text file
Reply With Quote #9

Quote:
Originally Posted by .Dare Devil. View Post
@Bugsy, your code doesn't make sense at all but still going to point out some things:
*What if replaced word is inside your block but is larger than old word, that much larger that it will need to go
to the new block?
Sorry that you don't understand it but try it and see, it does work. The only issue that I'm aware of at this point is:
  • When an szFind[] value gets cut-off between file reads around the buffer boundary location. Half of szFind will be at the end of one read while the other half will fall in the beginning of the next read. If the size of this file is known before-hand then the buffer can be sized accordingly to avoid this issue.
  • When szReplaceWith[] length exceeds szFind[] length and there is not enough room in the buffer, this should only impact files that have a size close to, or multiples of, the buffer size. I didn't realize this while writing the code and testing. My tests all used a szReplaceWith that was shorter than szFind. I will fix this issue. * Code updated *
Quote:
Originally Posted by .Dare Devil. View Post
The block size should be the string size of szFind and then
read one block from pos 0, check it, then read another block from pos 1 and so on...
or:
block size can also be szFind * x, it would be faster.
x = (filesize /size:szFind) * size:zsFind.
Still tho, pawn is ... horrible language, not sure how you can hold the block size of that huge.
For example 1024*10
while writing/updating word then
if string size:szFind => string size:szReplaceWith
You have to move all chars back by: size:szFind - string size:szReplaceWith, from the end of to the file, to the find pos of:szFind

if size:szFind =< string size:szReplaceWith then same but opposite way.

replace function will only work if you read the whole file into your block.
I don't have the patience to understand what you're trying to say. Feel free to write it as you think is better and we can take a look.
__________________

Last edited by Bugsy; 05-23-2015 at 21:28.
Bugsy is offline
aron9forever
Veteran Member
Join Date: Feb 2013
Location: Rromania
Old 05-24-2015 , 08:01   Re: Edit a word inside a text file
Reply With Quote #10

thanks for posting guys, but I used ham's implementation with reading line by line
__________________
Meanwhile, in 2050:
Quote:
Originally Posted by aron9forever
useless small optimizations
Quote:
Originally Posted by Black Rose View Post
On a map that is 512x512x128 units you end up with 3,355,443,200,000 different "positions". To store each one of those positions individually in the variable "user_or" you need 12 terabytes of memory.
aron9forever is offline
Reply



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 11:43.


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