2016-10-06 10 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

Комплект содержимого должен работать нормально с некоторыми незначительными корректировками. Вот пример того, как он должен работать (это все в пределах вашего внешнего цикла Еогеасп):

$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 
    } 

} 

 Смежные вопросы

  • Нет связанных вопросов^_^