user
Many systems offer the ability to open a file for writing, such that any data written will be appended to the end of the file. Further, the file operations will always adjust the position pointer to guarantee the end of the file, even in a multitasking environment.

This feature is most useful in the case of log files, where many jobs may be appending to the log file at the same time, or where care *must* be taken to avoid concurrently overwriting the same record from another job.

Task

Given a two record sample for a mythical "passwd" file:

* Write these records out in the typical system format.
  + Ideally these records will have named fields of various types.
* Close the file, then reopen the file for append.
  + **Append** a new record to the file and close the file again.
  + Take appropriate care to avoid concurrently overwrites from another job.
* Open the file and demonstrate the new record has indeed written to the end.

Source record field types and contents.

| account | password | UID | GID | fullname,office,extension,homephone,email | directory | shell |
| --- | --- | --- | --- | --- | --- | --- |
| string | string | int | int | struct(string,string,string,string,string) | string | string |
| jsmith | x | 1001 | 1000 | Joe Smith,Room 1007,(234)555-8917,(234)555-0077,jsmith@rosettacode.org | /home/jsmith | /bin/bash |
| jdoe | x | 1002 | 1000 | Jane Doe,Room 1004,(234)555-8914,(234)555-0044,jdoe@rosettacode.org | /home/jdoe | /bin/bash |

Record to be appended.

| account | password | UID | GID | fullname,office,extension,homephone,email | directory | shell |
| --- | --- | --- | --- | --- | --- | --- |
| string | string | int | int | struct(string,string,string,string,string) | string | string |
| xyz | x | 1003 | 1000 | X Yz,Room 1003,(234)555-8913,(234)555-0033,xyz@rosettacode.org | /home/xyz | /bin/bash |

**Resulting file format:** should mimic Linux's /etc/passwd file format with particular attention to the "," separator used in the GECOS field. But if the specific language has a particular or unique format of storing records in text file, then this format should be named and demonstrated with an additional example.

**Expected output:**

```
Appended record: xyz:x:1003:1000:X Yz,Room 1003,(234)555-8913,(234)555-0033,xyz@rosettacode.org:/home/xyz:/bin/bash

```

**Finally:** Provide a summary of the language's "append record" capabilities in a table. eg.

Append Capabilities.

| Data Representation | | IO Library | Append Possible | Automatic Append | Multi-tasking Safe |
| --- | --- | --- | --- | --- | --- |
| In core | On disk |
| C struct | CSV text file | glibc/stdio | ☑ | ☑ | ☑ (Not all, eg NFS) |

Alternatively: If the language's appends can not guarantee its writes will **always** append, then note this restriction in the table. If possible, provide an actual code example (possibly using file/record locking) to guarantee correct concurrent appends.
assistant
(formerly Perl 6)

**Works with**: Rakudo version 2017.09

This is kind of silly as it takes a string, converts it to a record, and then instantly converts it back to a string to write out to a file. Most of the "record handling" code is just demonstrating a possible way to store records in memory. It really has nothing to do with appending a string to a file.

```
class record {
    has $.name;
    has $.password;
    has $.UID;
    has $.GID;
    has $.fullname;
    has $.office;
    has $.extension;
    has $.homephone;
    has $.email;
    has $.directory;
    has $.shell;

    method gecos { join ',', $.fullname, $.office, $.extension, $.homephone, $.email }

    method gist {
        join ':',
        $.name,
        $.password,
        $.UID,
        $.GID,
        self.gecos,
        $.directory,
        $.shell;
    }
};

my $fname = 'foo.fil';

given $fname.IO.open(:w) { .close }; # clear file

sub append ($file, $line){
    my $fh = $file.IO.open(:a) or fail "Unable to open $file";
    given $fh {
        # Get a lock on the file, waits until lock is active
        .lock;
        # seek to the end in case some other process wrote to
        # the file while we were waiting for the lock
        .seek(0, SeekType::SeekFromEnd);
        # write the record
        .say: $line;
        .close;
    }
}

sub str-to-record ($str) {
    my %rec = <name password UID GID fullname office extension
      homephone email directory shell> Z=> $str.split(/<[:,]>/);
    my $user = record.new(|%rec);
}

for
  'jsmith:x:1001:1000:Joe Smith,Room 1007,(234)555-8917,(234)555-0077,jsmith@rosettacode.org:/home/jsmith:/bin/bash',
  'jdoe:x:1002:1000:Jane Doe,Room 1004,(234)555-8914,(234)555-0044,jdoe@rosettacode.org:/home/jdoe:/bin/bash'
-> $line {
        my $thisuser = str-to-record $line;
       $fname.&append: $thisuser.gist;
}

put "Last line of $fname before append:";
put $fname.IO.lines.tail;

$fname.&append: str-to-record('xyz:x:1003:1000:X Yz,Room 1003,(234)555-8913,(234)555-0033,xyz@rosettacode.org:/home/xyz:/bin/bash').gist;

put "Last line of $fname after append:";
put $fname.IO.lines.tail;

```

Output:

```
Last line of foo.fil before append:
jdoe:x:1002:1000:Jane Doe,Room 1004,(234)555-8914,(234)555-0044,jdoe@rosettacode.org:/home/jdoe:/bin/bash
Last line of foo.fil after append:
xyz:x:1003:1000:X Yz,Room 1003,(234)555-8913,(234)555-0033,xyz@rosettacode.org:/home/xyz:/bin/bash
```

Append Capabilities.

| Data Representation | | IO Library | Append Possible | Automatic Append | Multi-tasking Safe |
| --- | --- | --- | --- | --- | --- |
| In core | On disk |
| Class | Text file | Whichever is provided by the underlying VM | ☑ | ☑ | ☑ Advisory lock Depends on OS and VM |

Note that advisory locks do not prevent some other program (if it doesn't use flock) from unexpectedly writing to the file.