0

I have a very large file that consists of a single string. Because of the size of the file, I do not want to read the entire string into memory.

The last character will always be a closing bracket ] as this string is a json array. I want to insert a small json object (represented as a string) immediately before that closing bracket. I have seen a few ideas, but cannot get anything to work.

As you can see, I am trying to open the file and use fseek to move the file pointer to just in front of the ]. Then I try to write the new string into the existing string at that position.

However, the effect of this is simply to append the new string to the end of the existing string, which is not what I want.

As a simplified example, let's say the file starts out containing this string:

[{"name":"alice","city":"london"}]

And then I want to add a second person to this list using this code:

$new_person = ",{\"name\":\"bob\",\"city\":\"paris\"}";

$filename = "people.json";
$fh = fopen($filename, "a+");
$filesize = filesize($filename);
$stat = fstat($fh);
fseek($fh, $stat[$filesize]-1);
fwrite($fh, $new_person);
fclose($fh); 

But what I wind up with is a file that contains this string:

[{"name":"alice","city":"london"}],{"name":"bob","city":"paris"}

My PHP skills are terrible. I can't tell if my fseek is pointing to the wrong spot or if the issue is elsewhere. Thanks for any help.

AndroidDev
  • 20,466
  • 42
  • 148
  • 239

2 Answers2

2

From the docs (emphasis mine):

a+: Open for reading and writing; place the file pointer at the end of the file. If the file does not exist, attempt to create it. In this mode, fseek() only affects the reading position, writes are always appended.

Use r+ mode instead, and instead of fstat you can do:

fseek($fh, -1, SEEK_END);
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • fopen does the same. All file contents will be loaded to memory – Alive to die - Anant Mar 13 '20 at 04:39
  • Thank you. I suspected that it might have something to do with that, but misread the docs. – AndroidDev Mar 13 '20 at 04:41
  • @NiettheDarkAbsol anyhow pointer have to reach to the last line to append data. – Alive to die - Anant Mar 13 '20 at 04:43
  • Actually, @AnantSingh---AlivetoDie you raise an interesting issue. There really isn't any reason that I need to append at the end of the file. I can just add this object at the beginning of the array. – AndroidDev Mar 13 '20 at 04:45
  • 1
    @AnantSingh---AlivetoDie So? That doesn't involve reading the file into memory, that just involves moving the pointer along. *Absolute worst case* the append causes the file to exceed its current file allocation block and get pushed into a new one. Even then, big deal. – Niet the Dark Absol Mar 13 '20 at 04:48
  • @NiettheDarkAbsol got your point reading comment under this answer:- https://stackoverflow.com/a/162262/4248328 – Alive to die - Anant Mar 13 '20 at 04:54
0

Please try the following code to get your solution, i have tested and its work fine...

try{
    $new_person = ",{\"name\":\"bob\",\"city\":\"paris\"}]";
    $filename = "people.json";
    $fh = fopen($filename, "a+");
    $stat = fstat($fh);
    ftruncate($fh, $stat['size'] - 2);
    fwrite($fh, $new_person);
    fclose($fh); 
}catch(Exception $exc){
    echo($exc->getMessage());
}
Abdul Rahman
  • 1,669
  • 4
  • 24
  • 39