Powershell实时读取文件并输出到语音

时间:2018-07-26 18:15:38

标签: powershell speech

我正在寻找的是使用powershell并将文件内容读取到语音合成模块中。

此示例的文件名为echo 'arr=(' > temp add() { echo item >> temp; } ... export -f add ... add & ... echo ')' > temp source temp rm temp

“语音”模块的开始:

read.txt

这一次起作用。我喜欢在每次初次读取后使用Add-Type -AssemblyName System.speech $Narrator1 = New-Object System.Speech.Synthesis.SpeechSynthesizer $Narrator1.SelectVoice('Microsoft Zira Desktop') $Narrator1.Rate = 2 $Location = "$env:userprofile\Desktop\read.txt" $Contents = Get-Content $Location Get-Content $Location -wait -Tail 2 | where {$Narrator1.Speak($Contents)} 擦拭Clear-Content,让powershell等待,直到将新行添加到read.txt文件中,然后再次对其进行处理以说出内容。我相信我也可以使用read.txt

使它在后台运行

非常感谢您的协助。

斯科特

2 个答案:

答案 0 :(得分:1)

我不认为循环是答案,我将使用FileSystemWatcher来检测文件何时已更改。试试这个:

$fsw = New-Object System.IO.FileSystemWatcher
$fsw.Path = "$env:userprofile\Desktop"
$fsw.Filter = 'read.txt'

Register-ObjectEvent -InputObject $fsw -EventName Changed  -Action {
    Add-Type -AssemblyName System.speech
    $Narrator1 = New-Object System.Speech.Synthesis.SpeechSynthesizer
    $Narrator1.SelectVoice('Microsoft Zira Desktop')
    $Narrator1.Rate = 2

    $file = $Event.SourceEventArgs.FullPath

    $Contents = Get-Content $file
    $Narrator1.Speak($Contents)
} 

答案 1 :(得分:0)

您唯一的问题是您意外地在$Contentswhere)脚本块中使用了先前分配的Where-Object变量,而不是$_(代表< em>当前管道对象:

Get-Content $Location -Wait -Tail 2 | Where-Object { $Narrator1.Speak($_) }

Get-Content $Location -Wait将每秒轮询输入文件(此处为$Location)以检查新内容,并将其通过管道(仅-Tail参数)适用于文件的初始读取;添加新行后,它们会通过 all 传递。)

管道将无限期存活-直到您删除 $Location文件或中止处理。

由于命令是 blocking ,因此您显然需要另一个会话/进程才能将内容添加到文件$Location,例如另一个PowerShell窗口或具有打开和修改文件的文本编辑器其内容。

您可以使用>>追加保留到文件中,但这将使文件不断增长。

丢弃文件的先前内容,您确实必须使用Clear-Content ,正如您所说的那样,它会截断现有文件无需重新创建,因此可以使管道保持活动状态;例如:

Clear-Content $Location
'another line to speak' > $Location

注意事项:特殊字符。 !?之类的语音似乎会导致静音。如果有人知道为什么,请告诉我们。 docs没有立即提供线索。


关于后台操作

具有后台工作,奇怪的是,Clear-Content / >组合似乎无法正常工作;如果有人知道为什么,请告诉我们。

但是,使用>>-会增大文件大小-确实可以。

以下代码段演示了使用后台作业来保持语音输入的状态,即将其添加到指定文件中(有一定延迟),直到发送特殊的输入结束字符串为止:

# Determine the input file (on the user's desktop)
$file = Join-Path ([environment]::GetFolderPath('Desktop')) 'read.txt'

# Initialize the input file.
$null > $file

# Define a special string that acts as the end-of-input marker.
$eofMarker = '[quit]'

# Start the background job (PSv3+ syntax)
$job = Start-Job { 
  Add-Type -AssemblyName System.speech

  $Narrator1 = New-Object System.Speech.Synthesis.SpeechSynthesizer

  $Narrator1.SelectVoice('Microsoft Zira Desktop')

  $Narrator1.Rate = 2

  while ($true) { # A dummy loop we can break out of on receiving the end-of-input marker
    Get-Content $using:file -Wait | Where-Object { 
      if ($_ -eq $using:eofMarker) { break } # End-of-input marker received -> exit the pipeline.
      $Narrator1.Speak($_) 
    }
  }

  # Remove the input file.
  Remove-Item -ErrorAction Ignore -LiteralPath $using:file

}

# Speak 1, 2, ..., 10
1..10 | ForEach-Object {
  Write-Verbose -Verbose $_
  # !! Inexplicably, using Clear-Content followed by > to keep
  # !! replacing the file content does *not* work with a background task.
  # !! >> - which *appends* to the file - does work, however.
  $_ >> $file
}

# Send the end-of-input marker to make the background job stop reading.
$eofMarker >> $file

# Wait for background processing to finish.
# Note: We'll get here long before the background job has finished speaking.
Write-Verbose -Verbose 'Waiting for processing to finish to cleanup...'
$null = Receive-Job $job -wait -AutoRemoveJob