F# 用流写入二进制文件

F# 用流写入二进制文件,f#,F#,如何通过temp目录中的streams下载图像文件,我有以下代码,我被卡住了,需要seek和count部分的指导。有一些包装器方法,但出于RAM效率的原因,我特别寻找while循环方法 写作 let tempFileName = Path.GetTempFileName() let request = WebRequest.CreateHttp "http://example.com/image.png" use response = request.GetResponse() :?>

如何通过temp目录中的streams下载图像文件,我有以下代码,我被卡住了,需要seek和count部分的指导。有一些包装器方法,但出于RAM效率的原因,我特别寻找while循环方法

写作

let tempFileName = Path.GetTempFileName()

let request = WebRequest.CreateHttp "http://example.com/image.png"
use response = request.GetResponse() :?> HttpWebResponse
use stream = response.GetResponseStream()

let buffer = Array.zeroCreate 1024
use reader = new BinaryReader(stream)

use memoryStream = new MemoryStream()
use fileStream = new FileStream(tempFileName, FileMode.Open)

while not (reader.PeekChar() <> -1) do
    fileStream.Write(reader.ReadBytes(1024), 0, 1024)

return Ok (tempFileName)
let tempFileName=Path.GetTempFileName()
let request=WebRequest.CreateHttp“http://example.com/image.png"
使用response=request.GetResponse():?>HttpWebResponse
使用stream=response.GetResponseStream()
让buffer=Array.zeroCreate 1024
使用读取器=新二进制读取器(流)
使用memoryStream=新的memoryStream()
使用fileStream=newfilestream(tempFileName,FileMode.Open)
而不是(reader.PeekChar()-1)执行以下操作
fileStream.Write(reader.ReadBytes(1024)、0、1024)
返回Ok(tempFileName)

首先,我注意到,尽管您正在创建一个
缓冲区
数组,但实际上并没有使用它。其次,当我查看时,特别是的文档时,我注意到它接受一个int参数并返回一个字节数组。这一定意味着它每次都在分配一个新的数组,这似乎与您的意图相反(因为您提到了RAM效率,我假设您实际想要的是每次重复使用相同的缓冲区)

还有一个观察结果:ReadBytes方法表示,如果可用字节数较少,它可能返回一个小于请求大小的数组。您的代码当前未处理该情况

不过,所有这些问题都可以通过切换到新的解决方案来解决。使用此方法,您的
while
循环将如下所示:

while not (reader.PeekChar() <> -1) do
    let bytesRead = reader.Read(buffer, 0, 1024)
    fileStream.Write(buffer, 0, bytesRead)
如果bytesRead为0,您想更明确地说明跳过
Write
的事实,您可以添加
if
块:

let mutable bytesRead = -1
while not (bytesRead = 0) do
    bytesRead <- reader.Read(buffer, 0, 1024)
    if bytesRead > 0 then
        fileStream.Write(buffer, 0, bytesRead)
让可变字节读取=-1
而不是(bytesRead=0)执行
字节读取0
写入(缓冲区,0,字节读取)

最后一个
if
语句严格来说不是必需的,但是:
FileStream.Write
如果被要求写入0字节,则应该返回而不做任何操作。但是,由于在我能找到的任何地方都没有文档记录,为了安全起见,我在最后一个代码示例中添加了
if
语句。

从.NET 4.6.2开始,有System.IO.Stream#CopyTo方法:

namespace-fsharp-basics
模块图像爬虫=
开放系统.Net
开放系统
打开System.Text.RegularExpressions
让私有myurl=”https://cdn.pixabay.com/photo/2016/07/06/15/29/math-1500720_960_720.jpg"
let爬虫程序(url:string)=
让fileName=Regex.Match(url,@“\/([^\/]+)$”,RegexOptions.RightToLeft).Groups[1]。Value
let request=WebRequest.CreateHttp url
let response=request.GetResponse()
使用s=response.GetResponseStream()
使用w=File。创建文件名
s、 抄袭
w、 同花顺
[]
让主argv=
printfn“将保存JPEG文件”
爬虫myurl
printf“已保存”
0

您的问题是什么?你想做什么,你期望会发生什么,以及会发生什么?你指的是什么“查找和计数部分”?我所说的RAM效率是指那些包装器函数将整个图像数据读取到内存中,然后写入文件,这对于大型图像和多个请求来说是低效的。所谓效率,我指的是在数据块到达/传输时立即将其写入磁盘。
let mutable bytesRead = -1
while not (bytesRead = 0) do
    bytesRead <- reader.Read(buffer, 0, 1024)
    if bytesRead > 0 then
        fileStream.Write(buffer, 0, bytesRead)
namespace FSharpBasics

module ImageCrawler =

    open System.Net
    open System.IO
    open System.Text.RegularExpressions

    let private myurl = "https://cdn.pixabay.com/photo/2016/07/06/15/29/math-1500720_960_720.jpg"

    let crawler (url: string) =
        let fileName = Regex.Match(url, @"\/([^\/]+)$", RegexOptions.RightToLeft).Groups.[1].Value
        let request = WebRequest.CreateHttp url
        let response = request.GetResponse()
        use s = response.GetResponseStream()
        use w = File.Create fileName
        s.CopyTo w
        w.Flush true

    [<EntryPoint>]
    let main argv =
        printfn "JPEG file will be saved"
        crawler myurl
        printf "Saved"
        0