如何通过临时目录中的流下载图像文件,我遵循代码并且我遇到了困难,需要使用搜索和计数部分进行指导。有一些包装器方法,但我正在寻找专门针对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)
答案 0 :(得分:2)
首先,我注意到虽然您正在创建buffer
数组,但您实际上并未使用它。其次,当我查看BinaryReader
documentation,特别是ReadBytes
method的文档时,我注意到它需要一个int参数并返回一个字节数组。这必然意味着它每次都会分配一个新数组,这似乎与你想要的相反(因为你提到RAM效率,我认为你真正想要的是重新 - 每次使用相同的缓冲区。)
还有一个观察结果:ReadBytes方法表示,如果可用的字节数较少,它可能会返回一个小于请求大小的数组。您的代码目前尚未处理此案例。
但是,通过切换到BinaryReader.Read(byte[], int, int)
method,可以修复所有这些问题。使用此方法,您的while
循环将类似于以下内容:
while not (reader.PeekChar() <> -1) do
let bytesRead = reader.Read(buffer, 0, 1024)
fileStream.Write(buffer, 0, bytesRead)
现在我们正在跟踪每个Read
操作读取的字节数,我们可以摆脱PeekChar
调用并节省一些时间(调用{{1你下载的东西并非没有成本,因为库必须下载下一个字节,然后将其保存在某个地方,以便下次调用PeekChar
时可以返回它。我们可以通过检查前一次调用读取的字节数来做到这一点:如果它是0,那么这意味着我们在流的末尾。为此,我们将Read
变量移出循环,这意味着将其变为一个可变变量,我们每次循环都会重复使用它:
bytesRead
或者,如果您希望稍微更明确一点,如果您在bytesRead为0时跳过let mutable bytesRead = -1
while not (bytesRead = 0) do
bytesRead <- reader.Read(buffer, 0, 1024)
fileStream.Write(buffer, 0, bytesRead)
,则可以添加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)
语句并非绝对必要,但是:if
如果要求写0字节,则应该返回而不做任何事情。但是,由于我没有在任何可以找到的地方记录,我在最后一个代码示例中添加了FileStream.Write
语句只是为了安全起见。
答案 1 :(得分:0)
从.NET 4.6.2开始,有 System.IO.Stream#CopyTo 方法:
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