下面的PowerShell命令无法复制整个文件;末尾总是缺少几个字符。
[System.IO.StreamWriter]::new('C:\TEMP\b.csv', [System.Text.Encoding]::UTF8).Write([System.IO.StreamReader]::new('C:\Temp\a.csv', [System.Text.Encoding]::GetEncoding('iso-8859-1')).ReadToEnd())
我怀疑这是因为编写器不刷新最后一位,因为这确实复制了整个文件:
$X = [System.IO.StreamReader]::new('C:\Temp\a.csv', [System.Text.Encoding]::GetEncoding('iso-8859-1'))
$Y = [System.IO.StreamWriter]::new('C:\TEMP\b.csv', [System.Text.Encoding]::UTF8)
$Y.Write($X.ReadAll())
$X.Dispose()
$Y.Dispose()
是否有可能在不创建引用读取器和写入器的变量的情况下处理(和刷新)读取器和写入器?
编辑:我使用StreamReader/Writer尝试了这一行程序,希望读取器的读缓冲区可以直接传输到写入器的写缓冲区,而不是等待读取器将整个文件读取到内存中,然后再写入。有什么技术可以做到这一点呢?
我个人发现没有声明一次性对象的代码通常更干净/更简洁,但我的重点是理解对象是否/如何处置自己,而不是样式。
没有“需要”回避变量或在一行上编写代码,但这种行为并不是我所期望的。在VBA中,人们可以像这样复制文件,并相信它将正确地自我处置,而不必声明变量并显式刷新(我认为)。
Sub Cpy()
With New Scripting.FileSystemObject
.CreateTextFile("c:\Temp\Out.txt").Write .OpenTextFile("C:\Temp\In.txt", ForReading).ReadAll
End With
End Sub
通过在Class_Terminate()
过程中编写适当的“清理”代码,可以在自定义VBA类中实现类似的行为。我假设,一旦行执行并且不再有与其关联的变量,StreamWriter将类似地通过垃圾收集在终止时刷新数据。
我还注意到,该文件仍处于锁定状态,在关闭PowerShell会话之前无法将其删除。有没有一种方法可以在不声明要使用的变量的情况下刷新内容并释放文件?
2条答案
按热度按时间5cg8jx4n1#
只是为了向您展示,使用
System.IO.File
、WriteAllText()
和ReadAllText()
的静态方法可以更容易地实现这一点。以下查询https://loripsum.net/ API以获取随机段落,并使用
iso-8859-1
编码写入文件。然后读取该文件并使用相同的编码写入副本,最后比较两个文件散列。如你所见,阅读和写作都是一句俏皮话。可以删除
using
语句,但需要使用完全限定的类型名称。将位置设置为用于测试的临时文件夹。
u0sqgete2#
System.IO.File
类的静态方法,不需要示例来表示需要调用.Close()
方法或显式处置的文件。[System.IO.File]::ReadLines()
和[System.IO.File]::WriteAllLines()
方法,但请注意,这种方法(A)总是在输出文件中使用平台原生[Environment]::NewLine
的换行符,而不管输入文件使用哪种换行符格式,并且(B)总是在这种格式中添加一个尾随换行符,即使输入文件没有尾随换行符。System.IO.FileStream
,这也需要显式处理(见下一节)。-Encoding
参数接受任何支持的编码,例如您的示例中的ISO-8859-1,则甚至可以使用PowerShell cmdlet:关于你的一般性问题:
从PowerShell(核心)7.2.1开始:
using
语句的构造,它允许自动*处置其类型实现System.IDisposable
接口的对象(对于文件I/O API,该接口隐式关闭文件)。using
开头的语句,但它们的用途不同-请参阅概念性的about_Using帮助主题。clean { ... }
(或cleanup { ... }
)块**,这允许执行任何必要的脚本级清理(处置对象)-请参阅RFC #294。是否从终结器调用
.Dispose()
方法取决于实现IDisposable
接口的每个类型。只有在这样的情况下,垃圾回收器才会自动最终处理对象。对于
System.IO.StreamWriter
和较低级别的System.IO.FileStream
类,情况似乎并非如此,因此在PowerShell中,您必须显式调用.Close()
或.Dispose()
,这最好从try
/catch
/finally
statement的finally
块完成。通过将对象构造和变量赋值结合起来,你可以在一定程度上减少仪式,但一个健壮的习语仍然需要大量的仪式:
帮助器函数
Use-Object
(下面的源代码)可以稍微缓解这一点:请注意,作为第一个参数传递的禁用对象是如何通过
$_
作为脚本块参数中的ARRAY引用的(通常,您可以使用$PSItem
代替$_
)。一种更具可读性的替代方案:
Use-Object
源代码: