Partial edits of an IFC file without rewriting it

This discussion was created from comments split from: All-in-One AEC package.

Comments

  • @Moult You probably don't have to mmap the IFC, I think that you can do the same thing with python open(), seek() and write() - partial overwriting and appending without having to rewrite the rest of the file.

  • @Moult I'll leave this here as at might be of interest to someone at some point. Here is a tiny script that changes a single IFC entity without rewriting the file, even if the updated entity is longer. It is ridiculously fast, 0.02 seconds with a 5MB test file. Just pass it the ID of the entity you want to replace and the content you want to replace it with:

    update-ifc.pl example.ifc 48 'IFCCARTESIANPOINT((0.,0.,10.))'
    

    This is a diff of before and after, you can see that it overwrites an entity near the beginning with a same-length empty comment, and appends the updated entity just before the ENDSEC at the end of the file:

    55c55
    < #48=IFCCARTESIANPOINT((0.,0.,0.));
    ---
    > /*                              */
    98307a98308
    > #48=IFCCARTESIANPOINT((0.,0.,10.));
    

    Here is the script:

    #!/usr/bin/perl
    use strict;
    use warnings;
    my ($ifc_path, $id, $append) = @ARGV;
    my $line = `grep -b '^#${id}[ =]' $ifc_path`;
    my ($offset, $string) = $line =~ m/^([0-9]+):(.*)\r$/;
    my $spaces = length($string) -4;
    my $comment = sprintf("/*%${spaces}s*/", ' ');
    open my $ifc_fh, '+<', $ifc_path;
    sysseek $ifc_fh, $offset, 0;
    syswrite $ifc_fh, $comment;
    $line = `grep -b '^ENDSEC;' $ifc_path`;
    my @offsets = $line =~ m/([0-9]+):ENDSEC;/g;
    $offset = pop @offsets;
    sysseek $ifc_fh, $offset, 0;
    syswrite $ifc_fh, "#$id=$append;\r\nENDSEC;\r\nEND-ISO-10303-21;";
    
    MoultJesusbillJanF
  • Is this also safer than overwriting it? You don't really risk file corruption if the write gets interrupted right?
    Also would it theoretically be possible to just comment the entity out instead of replacing it with empty space and roll back?

  • Looks promising. How would this affect file sizes? I can imagine these to balloon quite fast if we keep ammending to the file each time a change is introduced.
    Are there smart ways of 'compacting' these files through removal of the unnecessary bits?

  • @JanF You certainly do risk file corruption. In a normal 'save' you write everything out to a temporary file, then rename it, clobbering the original file - this rename is an atomic process so if you pull the plug you either have the original file and a part-written temporary file, or you have a complete new updated file - either result is at least a valid file.

    A way to deal with this would be to write out every change to a journal, so if the file gets corrupted you can wind back to a known good state and then apply updates from the journal.

    Commenting the original entity, would increase the length of the line by four bytes, this would require rewriting the rest of the file and shifting everything along by four bytes (still quicker than regenerating the entire IFC from the model).

  • @mrhe said:
    Looks promising. How would this affect file sizes? I can imagine these to balloon quite fast if we keep ammending to the file each time a change is introduced.
    Are there smart ways of 'compacting' these files through removal of the unnecessary bits?

    You can compact it just by removing all single-line empty comments:

    egrep -v '^\/\* *\*\/$' example.ifc > _temp.ifc && mv _temp.ifc example.ifc
    
  • I split this thread to make it easier to find again.

    duncanMoult
Sign In or Register to comment.