【问题标题】:Append to Beginning of File追加到文件开头
【发布时间】:2021-12-13 04:04:59
【问题描述】:

背景

我必须运行SqlCmdBcp 才能得到一个Sql 表的输出。 有更好的方法,但这是我可以使用的。

首先,我运行SqlCmd 来获取表头并保存到C:\headers.csv

SqlCmd -S Server -d Database -Q "set nocount on; select top 0 * from TableName;" -o "C:\headers.csv" -s "," -W

接下来,我运行Bcp 从表中获取数据并保存到C:\data.csv

Bcp TableName out "C:\data.csv" -S Server -d Database -T -t , -c

我最终得到了两个文件 headers.csvdata.csv。我需要将headers.csv 的内容附加到data.csv 的开头。

我的尝试

令人讨厌的是,SqlCmd 在标题后添加了一行连字符。我去掉那一行:

Get-Content -Path "C:\headers.csv" -TotalCount 1 | Out-File -FilePath "C:\final-output.csv" -Force

这就是我想出的做两个文件的最终“连接”:

[System.IO.File]::AppendAllLines("C:\final-output.csv",[System.IO.File]::ReadLines("C:\data.csv"))

我在 Server 2016 上运行。使用 PowerShell 是否有更快的方法来读取或写入 final-output.csv

【问题讨论】:

  • 为什么不将两个结果都存储在变量中,然后附加它们,而不是导出到文件然后再次读取文件?您可以编辑添加命令以获得结果SqlCmdBcp 的问题
  • 这可能是比写入文件更好的方法。只需要弄清楚命令。我在 Server 2016 上可以使用 SQLPS 模块卡住。添加了SqlCmdBcp 的命令。
  • 不,您不需要将 headers.csv 的内容附加到 data.csv 的开头。您需要做相反的事情 - 将 data.csv 附加到 headers.csv。您可以使用type data.csv >> headers.csv 直接从命令提示符处执行此操作。

标签: .net powershell


【解决方案1】:

这不是内置支持的操作,附加通常在文件的end 完成。我知道的唯一选择是读入当前内容,在位置 0 插入新内容,然后重新写入文件。为此,我们将使用List 来帮助完成此过程并防止字符串/数组连接:

注意:此示例假定目标文件编码为 UTF8。 .NET 无法知道当前文件的编码是什么,因此您需要提前知道这一点并相应地更改encoding。查看前面链接中的派生类型,了解 PowerShell/.NET 开箱即用支持的编码。

# $newContent should be what you want to append to the start of the existing file
# If $newContent is already an array of text lines then you do not need to worry about
# splitting on `[Environment]::NewLine` and you can pass $newContent in directly.
$newContent = [System.Generic.Collections.List[string]]::new(( $newContent -split [System.Environment]::NewLine ))

# $filePath should be the file you want to append to the beginning of
$newContent.Add(( Get-Content $filePath ))

# Write back out to file, overwriting the existing content ($newContent should have it all)
$newContent | Out-File -Encoding UTF8 -Force $filePath

不幸的是,这不会特别高效,尽管使用List[string] 可以防止对现有内容进行不必要的复制,这应该会有所帮助,尤其是在文件较大的情况下。缺点是您必须在最后读取所有现有内容(或者先读取文件内容并在索引0 处插入新内容,尽管此示例不这样做),所以 必须重写整个文件。正如我在开头提到的,直接写入文件的开头而不是结尾不是受支持的操作。

【讨论】:

    【解决方案2】:

    我对这两个命令如何工作的了解不多,所以如果我错了,请纠正我。
    假设 SqlCmdarray 返回到标准输出,如果我们删除 -o "C:\headers.csv",我们可以像这样存储标头:

    $headers = SqlCmd -S Server -d Database -Q "set nocount on; select top 0 * from TableName;" -s "," -W
    $headers = $headers[0]
    

    如果它没有返回一个数组而实际上返回了一个多行字符串,那么这应该可以工作:

    $headers = SqlCmd -S Server -d Database -Q "set nocount on; select top 0 * from TableName;" -s "," -W
    $headers = $headers -split '\r?\n' | Select-Object -First 1
    

    然后,假设如果我们从Bcp 中删除out "C:\data.csv",它会将Table 的内容返回到stdout,我们可以将结果存储到$data 变量中:

    $data = Bcp TableName -S Server -d Database -T -t , -c
    

    现在您应该能够执行以下操作来合并两个变量:

    $headers, $data | Out-File path\to\csv.csv
    

    一个简单的例子:

    # This would be a multi-line string
    $headers = @'
    col1,col2,col3
    --------------
    '@
    
    $headers = $headers -split '\r?\n' | Select-Object -First 1
    
    # Then something random for $data
    $data = 0..5 | ForEach-Object { $x = Get-Random; "$x,$x,$x" }
    
    # Lastly:
    PS \> $headers, $data
    col1,col2,col3
    1975011385,1975011385,1975011385
    858903029,858903029,858903029
    1830294256,1830294256,1830294256
    1252960811,1252960811,1252960811
    1400092566,1400092566,1400092566
    1412627916,1412627916,1412627916
    
    # If we pass this to Out-File it should look exactly as we're seeing it on the console
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-28
      • 2013-06-03
      • 2010-10-16
      • 2013-01-17
      • 2015-03-31
      • 2017-02-14
      • 2013-09-19
      • 1970-01-01
      相关资源
      最近更新 更多