Datafile-Array

 view release on metacpan or  search on metacpan

lib/Datafile/Array.pm  view on Meta::CPAN

    if ( ref $data ne 'ARRAY' && ref $data ne 'HASH' && !@field_names ) {
        if ( -f $filename ) {
            unlink($filename)
                or return ( 0, ["WARNING: unable to delete file $filename"] );
            return ( 1, ["SUCCESS: file $filename is deleted"] );
        }
        croak
"datafile::array::writearray: 'data' parameter must be an ARRAY or HASH reference";
    }

    my @messages = ();
    push @messages,
        "# writearray: fields=@field_names\n",
        "# opts: "
        . join( ", ", map { "$_=$opts->{$_}" } sort keys %$opts ) . "\n"
        if $verbose;

    my $tmp = "$filename.tmp";
    open( my $fh, '>:encoding(UTF-8):crlf', $tmp )
        or return ( 0, ["ERROR: cannot open '$tmp' for writing: $!"] );

    if ( my $comment = $opts->{comment} ) {
        my @lines = ref($comment) eq 'ARRAY' ? @$comment : split( /\n/, $comment );
        print $fh "$comment_char $_\n" for @lines;
        if ($verbose) { push @messages, "> $comment_char $_\n" for @lines }
    }

    my $prefix_hdr = $prefix ? 'H' . $delim : '';
    my $prefix_row = $prefix ? 'R' . $delim : '';

    if ( $header && @field_names ) {
        print $fh $prefix_hdr . join( $delim, @field_names ) . "\n";
        push @messages,
            "> " . $prefix_hdr . join( $delim, @field_names ) . "\n"
            if $verbose;
    }

    my $record_count = 0;
    my @records =
        ref($data) eq 'HASH' ? sort keys %$data : 0 .. $#$data;

    for my $key (@records) {
        my $rec = ref($data) eq 'HASH' ? $data->{$key} : $data->[$key];
        my @values = map { defined( $rec->{$_} ) ? $rec->{$_} : '' } @field_names;
        my $line   = $prefix_row . join( $delim, @values );
        print $fh $line . "\n"
            or return ( 0, ["ERROR: write error to '$tmp': $!"] );
        $record_count++;
    }
    print $fh "#EOF\n" if $comment_char eq '#';
    close $fh
        or return ( 0, ["ERROR: failed to close '$tmp': $!"] );

    if ($backup && -f $filename) {
        rename( $filename, $filename . '.bak' )
            or push @messages,
            "WARNING: backup to ${filename}.bak failed: $!";
    }
    rename( $tmp, $filename )
        or return ( 0, ["ERROR: failed to rename '$tmp' to '$filename': $!"] );
    chmod $prot, $filename;

    push @messages,
        "- renamed $tmp to $filename\n",
        "- $record_count data records written to $filename\n"
        if $verbose;
    return ( $record_count, \@messages );
}

1;

__END__

=head1 NAME

Datafile::Array - Pure-Perl utilities for reading and writing delimited data files

=head1 LICENSE

This module is free software.

You can redistribute it and/or modify it under the same terms as Perl itself.

=head1 SYNOPSIS

  use Datafile::Array qw(readarray writearray parse_csv_line);

  my @records;
  my @fields;

  my ($count, $msgs) = readarray('data.txt', \@records, \@fields, {
      delimiter    => ';',
      csvquotes    => 1,        # enable proper CSV quoted fields and multi-line
      has_headers  => 1,
      prefix       => 1,        # expect 'H' header and 'R' data lines
      trim_values  => 1,
      verbose      => 1,
  });

  # @records now contains array of hashes
  # @fields contains the detected or provided field names

  writearray('data.txt', \@records, \@fields, {
      header  => 1,
      prefix  => 1,
      backup  => 1,
      comment => 'Exported on ' . scalar localtime,
  });

=head1 DESCRIPTION

Lightweight pure-Perl module for reading and writing simple delimited data files.
Supports optional CSV-style quoted fields (including multi-line records), automatic or explicit headers,
prefix lines (H/R convention), search filtering, trimming, and safe atomic writes.

=head1 FUNCTIONS

=head2 readarray($filename, $data_ref, $fields_ref, \%options)

Loads delimited data into an array of hashes (or hash of hashes if using keys).



( run in 0.525 second using v1.01-cache-2.11-cpan-5623c5533a1 )