如何在Write

问题描述

我们使用excel作为客户端的配置文件。但是,我们的进程仅在linux服务器上运行。我们需要获取一个文件,使用新信息更新所有客户端工作簿,然后提交给GitLab。然后,用户将其签出,添加自己的更改,提交回GitLab,然后将工作簿升级到Server A的过程。

使用nodeJS(exceljs),此过程效果很好

另一台服务器上的另一个过程是使用perl拾取工作簿,然后将每张工作表另存为csv文件

问题是,写入的内容是原始工作表中的数据,而不是更新的更改。 Perl和nodejs都是如此。在文章的末尾显示了将perl和nodejs xlsx转换为csv的代码

尝试过的模块 perl :Spreadsheet :: ParseExcel;电子表格:: XLSX; nodejs :node-xlsx,exceljs

我认为这与Microsoft在excel包装器中使用XML有关,它将旧版本保留为历史记录,并且由于它是原始工作表名称,因此将其拉出而不是更新的最新版本。

当我在Excel中手动打开时,新信息与预期的一样一切正常。

当我使用“另存为...”而不是“保存”时,perl进程能够正确地将更新的工作表写为csv。因此,我们的解决方法是让用户在将其多余的更改提交给GitLab之前始终将其另存为“ ..”。我们想依靠培训,但是庞大的用户和客户数量使用户难以相信用户将“另存为...”。

升级到服务器A的过程中,是否可以复制“另存为...”,或者至少能够确定文件是否已正确保存?我想坚持使用excelJS,但是我将使用一切必要的方法来复制“另存为...”,这似乎会重新编译工作簿。

除了nodejs之外,我还可以使用perl,python,ruby(无论花费多少)来确保csv创建过程能够吸收新的变化。

感谢您的时间和帮助。

#!/usr/bin/env perl 
    
     use strict; 
     use warnings; 
     use Carp; 
     use Getopt::Long; 
     use Pod::Usage; 
     use File::Basename qw/fileparse/; 
     use File::Spec; 
     use Spreadsheet::ParseExcel; 
     use Spreadsheet::XLSX; 
     use Getopt::Std;
       
     my %args = (); 
     my $help = undef; 
     Getoptions( 
     \%args,'excel=s','sheet=s','man|help'=>\$help,) or die pod2usage(1); 
      
     pod2usage(1) if $help; 
     pod2usage(-verbose=>2,exitstatus=>0,output=>\*STDOUT) unless $args{excel} || $args{sheet}; 
     
     pod2usage(3) if $help; 
     pod2usage(-verbose=>2,exitstatus=>3,output=>\*STDOUT) unless $args{excel}; 
     
    
     if (_getSuffix($args{excel}) eq ".xls") { 
     my $file = File::Spec->rel2abs($args{excel}); 
      
     if (-e $file) { 
     print _XLS(file=>$file,sheet=>$args{sheet}); 
     } else { 
     exit 1;
     die "Error: Can not find excel file. Please check for exact excel file name and location. \nError: This Program is CASE SENSITIVE. \n"; 
     } 
     } 
     elsif (_getSuffix($args{excel}) eq ".xlsx") { 
     my $file = File::Spec->rel2abs($args{excel}); 
     
     
     if (-e $file) { 
      print _XLSX(file=>$file,sheet=>$args{sheet});
     } 
     else { 
     exit 1;
     die "\nError: Can not find excel file. Please check for exact excel file name and location. \nError: This Program is CASE SENSITIVE.\n"; 
     }
     } 
     else { 
     exit 5; 
     }
      
      
     sub _XLS { 
     my %opts = ( 
     file => undef,sheet => undef,@_,); 
      
     my $aggregated = (); 
     my $parser = Spreadsheet::ParseExcel->new(); 
     my $workbook = $parser->parse($opts{file}); 
      
     if (!defined $workbook) { 
     exit 3;
     croak "Error: Workbook not found"; 
     } 
      
     foreach my $worksheet ($workbook->worksheet($opts{sheet})) { 
     
     if (!defined $worksheet) { 
       exit 2;
       croak "\nError: Worksheet name doesn't exist in the Excel File. Please check the WorkSheet Name. \nError: This program is CASE SENSITIVE.\n\n";
     }
     
     my ($row_min,$row_max) = $worksheet->row_range(); 
     my ($col_min,$col_max) = $worksheet->col_range(); 
    
     foreach my $row ($row_min .. $row_max){ 
     foreach my $col ($col_min .. $col_max){ 
     my $cell = $worksheet->get_cell($row,$col); 
     if ($cell) {
         $aggregated .= $cell->value().','; 
     }
     else {
         $aggregated .= ',';
     }
     }
     $aggregated .= "\n"; 
     } 
     } 
     return $aggregated; 
     } 
      
      
      
     sub _XLSX { 
     eval {
     my %opts = ( 
     file => undef,); 
    
      
     my $aggregated_x = (); 
     my $excel = Spreadsheet::XLSX->new($opts{file}); 
      
    foreach my $sheet ($excel->worksheet($opts{sheet})) {
    
        if (!defined $sheet) { 
          exit 2;
          croak "Error: WorkSheet not found"; 
        } 
    
     if ( $sheet->{Name} eq $opts{sheet}) { 
            $sheet->{MaxRow} ||= $sheet->{MinRow}; 
            foreach my $row ($sheet->{MinRow} .. $sheet->{MaxRow}) { 
                    $sheet->{MaxCol} ||= $sheet->{MinCol}; 
                            foreach my $col ($sheet->{MinCol} .. $sheet->{MaxCol}) { 
                            my $cell = $sheet->{Cells}->[$row]->[$col]; 
                            if ($cell) {
                            $aggregated_x .= $cell->{Val}.','; 
                            }
                            else {
                                    $aggregated_x .= ',';
                            } 
                    }
             $aggregated_x .=  "\n"; 
            } 
     }
     } 
     return $aggregated_x; 
     } 
     
     };
     if ($@) {
     exit 3;
     }
     
     
     sub _getSuffix { 
     my $f = shift; 
     my ($basename,$dirname,$ext) = fileparse($f,qr/\.[^\.]*$/); 
     return $ext; 
     }
     
     
     
      sub _convertlwr{ 
      my $f = shift; 
      my ($basename,qr/\.[^\.]*$/); 
      return $ext; 
      }
var xlsx = require('node-xlsx')
var fs = require('fs')
var obj = xlsx.parse(__dirname + '/test2.xlsx') // parses a file
var rows = []
var writeStr = ""

//looping through all sheets
for(var i = 0; i < obj.length; i++)
{
    var sheet = obj[i]
    //loop through all rows in the sheet
    for(var j = 0; j < sheet['data'].length; j++)
    {
            //add the row to the rows array
            rows.push(sheet['data'][j])
    }
}

//creates the csv string to write it to a file
for(var i = 0; i < rows.length; i++)
{
    writeStr += rows[i].join(",") + "\n"
}

//writes to a file,but you will presumably send the csv as a      
//response instead
fs.writeFile(__dirname + "/test2.csv",writeStr,function(err) {
    if(err) {
        return console.log(err)
    }
    console.log("test.csv was saved in the current directory!")

解决方法

答案是不可能的。为了更新具有excel函数的工作簿中的数据,必须在Excel中将其打开以触发公式。就这么简单。

您可以将工作簿拆开,创建自己的javascript函数,通过它运行数据,然后将其写出,但是存在许多可能的问题,因此不建议这样做。

也许有一天,Microsoft将发布用于Linux的Linux Excel引擎API。但是这种事情仍然不太可能通过命令行调用而无需调用GUI。