2013-01-10 118 views
2

我不認爲我正在處理的這一小段代碼有任何實際應用,但我試圖繞過異步並似乎掙扎了一下。比方說,我想從雅虎提取歷史股票價格數據,將所有數據保存到單個csv文件,然後使用批量複製將其加載到SQL Server中。我並不擔心將數據加載到SQL Server中,但我想知道如何將數據寫入新的csv文件。可以/應該異步完成嗎?使用async讀取/寫入數據

據我所知,當抓取歷史數據時,沒有辦法在股票流中獲取股票,所以我抓住流並將其映射到一個新列表中,並在每個股票的前面添加股票行情項目。有時我會進行一次測試,我會得到一個沒有代碼的記錄,並且會有一個包含多個代碼的記錄(例如「MSFT,YHOO」)。

所以,我的問題是,如何將這些數據轉儲到一個單獨的csv文件而不會導致問題?其次,當我分割數據時,我得到一個空尾項目。什麼是最好的方法來放棄?

就像我說過的,我不知道這有什麼實際應用,但我正在努力學習,所以我希望你能原諒我的無知。感謝您的幫助,我非常感謝。下面是我有:

open System 
open System.IO 
open System.Web 
open System.Net 

let fromDate = new DateTime(2013, 1, 1) 

let getTickers = 
    "MSFT" :: "YHOO" :: [] 

let getData (ticker : string) = 
    async { 
     let url = System.String.Format("http://ichart.finance.yahoo.com/table.csv?s={0}&g=d&ignore=.csv&a={1}&b={2}&c={3}", ticker, fromDate.Month - 1, fromDate.Day, fromDate.Year) 

     Console.WriteLine(url) 

     let req = WebRequest.Create(url) 
     let! rsp = req.AsyncGetResponse() 
     use stream = rsp.GetResponseStream() 
     use reader = new StreamReader(stream) 

     let lines = 
      reader.ReadToEnd().Split('\n') 
      |> Seq.skip 1 // skip header 
      |> Seq.map (fun line-> (String.Format("{0}, {1}", ticker, line.ToString()))) 

     Seq.iter (fun x->printfn "%s" (x.ToString())) lines 
     () 
    } 

let z = 
    getTickers 
    |> List.map getData 
    |> Async.Parallel 
    |> Async.RunSynchronously 
+0

您可以發佈消息到一個代理,然後有一個單獨的線程,讓他們代理和寫入csv文件 –

+0

這可能屬於[codereview](http://codereview.stackexchange.com/),但您可能會發現這[[相關問題的答案]](http://stackoverflow.com/ a/11677368/162396)很有幫助。如果您只想將數據加載到SQL Server中,則不需要先將其寫入文件。 – Daniel

+0

@ovatsus - 我會研究一下。知道任何好的例子嗎? – nickfinity

回答

2

IMO,這是過頭了,但希望它表明你想知道:

open System 
open System.IO 
open System.Net 

let tickers = 
    [ 
    "MSFT" 
    "YHOO" 
    ] 

let getData (writer: TextWriter) ticker = 
    async { 
    let url = sprintf "http://ichart.finance.yahoo.com/table.csv?s=%s&g=d&ignore=.csv" ticker 
    let req = WebRequest.Create(url) 
    let! resp = req.GetResponseAsync() |> Async.AwaitTask 
    use stream = resp.GetResponseStream() 
    use reader = new StreamReader(stream) 
    let! lines = reader.ReadToEndAsync() |> Async.AwaitTask 
    let lines = 
     lines.Split('\n') 
     |> Seq.skip 1 
     |> Seq.filter ((<>) "") //skip empty lines 
    for line in lines do 
     do! writer.WriteLineAsync(String.Format("{0}, {1}", ticker, line)).ContinueWith(ignore) |> Async.AwaitTask 
    } 

let writeAllToFile path = 
    use writer = new StreamWriter(path=path) 
    tickers 
    |> Seq.map (getData writer) 
    |> Async.Parallel 
    |> Async.RunSynchronously 
    |> ignore 

writeAllToFile @"C:\quotes.csv" 
+0

太棒了,謝謝。現在確保我理解這一切。 – nickfinity

+0

這應該在運行時給出時髦的結果,特別是當有更多的代價時。 StreamWriter不是線程安全的。 –

+0

毫無疑問。如果他想避免這種情況,他必須同步寫入或使用排隊代理。 – Daniel