2016-10-06 34 views
0

輸入文件是一個固定寬度的txt文件。我的客戶通常在Excel中打開它並手動指定分欄符。我希望用逗號替換某些空格,以便我可以解析爲CSV並另存爲XLS或其他內容。將固定寬度的txt文件轉換爲CSV/set-content或out-file -append?

$columBreaks = 20, 35, 50, 80, 100, 111, 131, 158, 161, 167, 183 
[array]::Reverse($columBreaks) #too lazy to re-write array after finding out I need to iterate in reverse 

$files = get-childitem ./ |where-object {$_.Name -like "FileFormat*.txt"} 

foreach($file in $files) 
{ 
    $name = $file.Name.split(".") 
    $csvFile = $name[0]+".csv" 
    if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed 
    { 
     $text = (gc $file) 
     foreach ($line in $text) 
     { 
      foreach ($pos in $columBreaks) 
      { 
       #$line.Substring($char-1,3).replace(" ", ",") 
       $line = $line.Insert($pos,",") 
       #out-file -append? 
      } 
     } 
    } 
    #set-content? 
} 

那麼,寫出這些內容的最有效方法是什麼?我曾希望使用set-content,但我不認爲這是可能的,因爲我們正在逐行處理,所以我認爲我要麼必須爲set-content創建一行數組,要麼使用write-out - 追加每個迭代。有沒有更有效的方法來做到這一點?

回答

1

設置內容應該可以很好地進行一些小的調整。這裏是它如何工作的一個例子(這是你外層的foreach循環中的所有內容):

$csvFile = $file.BaseName 
    if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed 
    { 
     (gc $file | foreach { 
       $_.Insert($columBreaks[0],",").Insert($columBreaks[1],",").Insert($columBreaks[2],",").` 
       Insert($columBreaks[3],",").Insert($columBreaks[4],",").Insert($columBreaks[5],",").` 
       Insert($columBreaks[6],",").Insert($columBreaks[7],",").Insert($columBreaks[8],",").` 
       Insert($columBreaks[9],",").Insert($columBreaks[10],",") 
      }) | set-content $csvFile #note parenthesis around everything that gets piped to set-content 
    } 

順便說一句,而不是在分裂的文件名,你可以得到的名,不帶「」使用擴展名$file.BaseName

$csvFile = $file.BaseName + ".csv" 
+0

感謝您提供的基礎名稱提示。設置內容給我一個空管錯誤。 –

+0

我最初錯過了你的if語句。你應該能夠將設置內容位移到if塊中(緊隨'foreach($ line in $ text)' – morgb

+0

)我不認爲用foreach管道可以工作,我已經看到了幾個這個例子使用了foreach對象,但我努力將內部循環轉換爲所需的格式。 –

0

以下是工作代碼。修復了一些錯誤。

CD 'C:\\FOLDERPATH\' 
$filter = "FILE_NAME_*.txt" 

$columns = 11,22,32,42,54 

# DO NOT NEED TO REVERSE [array]::Reverse($columns) #too lazy to re-write array after finding out I need to iterate in reverse 

$files = get-childitem ./ |where-object {$_.Name -like $filter} 
$newDelimiter = '|' 

foreach($file in $files) 
{ 
    $file 

    $csvFile = 'C:\\FOLDERPATH\NEW_' + $file.BaseName + '.txt' 
    if (!(get-childitem ./ |where-object {$_.Name -like $csvFile})) #check whether file has been processed 
    { 

     $content | ForEach { 
      $line = $_ 
      $counter = 0 
      $columns | ForEach { 
       $line = $line.Insert($_+$counter, $newDelimiter) 
       $counter = $counter + 1 
       } 
      $line = $line.Trim($newDelimiter) 
      $line 
     } | set-content $csvFile 
    } 

}