Moro,
Miten streamreaderin readlineä käsketään lukemaan vain jokin tietty rivi streamin keskeltä?
Esim.
Tiedostossa on kolme riviä:
rivi 1
rivi 2
rivi 3
Haluan lukea tiedostosta pelkästään rivin 2. En halua käydä koko tiedostoa läpi ja katsoa jos rivi on kaksi, vain haluan lukea siis pelkästään tuon rivin 2. Miten onnistuu?
Ja haluan nimenomaan käyttää streamreaderia tuohon :)
joudut lukemaan rivejä alusta kunnes tulet haluamallesi riville
Dim oRead As System.IO.StreamReader 'avaa oread jossain... 'kutsu seuraavaa kunnes olet saanut haluamasi rivin LineIn = oRead.ReadLine()
eli käytännössä voit vaikka tehdä funktion joka ottaa parametrina ton streamin ja halutun rivin indeksin. Sitten vain funktiossa luet silmukassa readlinella niin monta kertaa että saat haluamasi rivin jonka sitten palautat funktiosta ulos.
esakom kirjoitti:
joudut lukemaan rivejä alusta kunnes tulet haluamallesi riville
Dim oRead As System.IO.StreamReader 'avaa oread jossain... 'kutsu seuraavaa kunnes olet saanut haluamasi rivin LineIn = oRead.ReadLine()eli käytännössä voit vaikka tehdä funktion joka ottaa parametrina ton streamin ja halutun rivin indeksin. Sitten vain funktiossa luet silmukassa readlinella niin monta kertaa että saat haluamasi rivin jonka sitten palautat funktiosta ulos.
Juu, juuri noin oon tuon homman tällä hetkellä toteuttanutkin. Mutta halusin nimenomaan lukea jonkin tietyn rivin, ja pelkästään sen tietyn rivin sieltä tiedostosta. On hölmöä lukea streamista kaikki rivit, jos en tarvitse kuin yhtä sieltä keskeltä.
Kikkare jossa tuota readlineä tarvitsen on oma tekemäni windows service joka pyörii koko ajan taustalla windoksessa. Pitää yrittää tehdä ko. servicestä mahdollisimman kevyt ja sen takia haluaisin juurikin lukea vain sen yhden rivin missä tiedän haluamani tekstin olevan.
Eikö todella ole mahdollista käskeä streamreaderin readlineä lukemaan vain jokin ennalta määrätty rivinumero?
Mieti hetki tekstitiedoston rakennetta levyllä, niin ymmärrät helposti tuonkin asian. Tiedosto ei ole levyllä riveinä vaan jatkuvana merkkijonona, jossa tietyt merkit tarkoittavat rivinvaihtoja. Ohjelmalla ei siis ole mitään muuta tapaa löytää tiettyä riviä kuin lukea eteenpäin kunnes on ohitettu tietty määrä rivinvaihtomerkkejä.
Metabolix kirjoitti:
Mieti hetki tekstitiedoston rakennetta levyllä, niin ymmärrät helposti tuonkin asian. Tiedosto ei ole levyllä riveinä vaan jatkuvana merkkijonona, jossa tietyt merkit tarkoittavat rivinvaihtoja. Ohjelmalla ei siis ole mitään muuta tapaa löytää tiettyä riviä kuin lukea eteenpäin kunnes on ohitettu tietty määrä rivinvaihtomerkkejä.
Aivan, hyvä kommentti.
Mikä olisi kevyein tapa lukea 250 rivisestä tiedostosta rivi nro 113 tietyin väliajoin? Miten raskasta on käydä tosiaan nuo kaikki läpi tuolla nykyisellä tavalla, siis sillä minkä esakom:kin mainitsi? Onko streamreader tähän paras(nopein) vaihtoehto?
No ei se kevyttäkään ole. Riippuu paljolti rivien pituudesta. Jos tuo ei kuitenkaan ole aikakriittinen kohta eikä "tietyi väliajoin" tarkoita mitään sekuntien kokoluokkaa, niin mikään katastrofi tuo tuskin on. Mitähän varten tuon kokoisesta tiedostosta pitää jatkuvasti lukea samaa riviä? Mikä sitä muuttaa, olisiko jotenkin mahdollista pitää yhteyttä pienemmillä tiedostoilla tai esimerkiksi piipuilla?
Metabolix kirjoitti:
No ei se kevyttäkään ole. Riippuu paljolti rivien pituudesta. Jos tuo ei kuitenkaan ole aikakriittinen kohta eikä "tietyi väliajoin" tarkoita mitään sekuntien kokoluokkaa, niin mikään katastrofi tuo tuskin on. Mitähän varten tuon kokoisesta tiedostosta pitää jatkuvasti lukea samaa riviä? Mikä sitä muuttaa, olisiko jotenkin mahdollista pitää yhteyttä pienemmillä tiedostoilla tai esimerkiksi piipuilla?
Teen vb.netillä harjoituksen vuoksi semmoisen palvelun joka hakee säätietoja eri sivuilta. Sivu, josta tiedot haetaan haalitaan ensin streamiin, josta luetaan tarvitavat rivit, eli juurikin tuo rivi 113. Palvelun olisi tarkoitus pyöriä windoksessa taustalla ja kirjoittaa säähavaintoja lokiin. Teen siihen vielä lisäksi käyttöliittymän jolla tuota palvelua voidaan ohjata; sulkea, käynnistää, selata tilastoja, lokeja, jne. Käyttäjä voi itse määrätä aikamääreen tuolla käyttäliittymällä säätietojen pollaamiseen. Tuo "tietyin väliajoin" tulee siis tarkoittamaan aikaa väliltä 1min - 24h. Palvelu hakee myös kerran päivässä sääkartan ja viiden vuorokauden ennusteen kuvina tietyilta nettisivuilta.
Tämä on eka vb.net projekti, niin pitää vain koittaa tutustua uusiin ominaisuuksiin, esim. tuohon streamreaderiin.
Harjoittelen vielä tätä .nettiä, mitä siis tarkoitat tuolla, että "olisiko mahdollista pitää yhteyttä pienemmillä tiedostoilla tai esimerkiksi piipuilla?" Mistään piipuista en ole mitään kuullutkaan. VB kutosta olen käyttänyt kovasti, mutten sieltäkään muista mitään näitä piipuista? :)
Tarkoitin vain, että jos tarkoituksena olisi pitää yhteyttä kahden ohjelman välillä, niin tiedostot eivät kannattaisi. Piippu (pipe) on sellainen hyvin paljon tiedoston tavoin toimiva tiedonsiirtokanava, ja niitä kannattaa usein käyttää, jos pitää kahden ohjelman välillä siirtää tietoa.
Tuollaisessa systeemissä varmaankin kelpaa hyvin tuo StreamReader. (Tuskin tuohon kovin monta muuta tapaa edes on.) Tietenkin jos tiedosto pysyy aina samana johonkin asti, on tehokasta hypätä sinne suorempaa tietä.
' Siirrytään tiedoston kohtaan Tavujen_Määrä StreamReader_Olio.BaseStream.Seek(Tavujen_Määrä, System.IO.SeekOrigin.Begin)
Erittäin hyvä neuvo. Sivu jolta säätiedot haen on samanlainen aina tietojen alkamiskohtaan asti. Eli tällä pääsen hyppäämään parsittavan tiedon lähelle ja lukemaan siitä rivit ilman että kahlaan koko streamia alusta läpi. Juurikin jotain tällaista hainkin. Kiitos vaan vastauksista.
Et kai kirjoita sitä sää sivua ensin tiedostoon ja siitä muistiin? Kannattanee ottaa se sivulta tuleva tavara pelkästään rammissa (muististreamissa), ja kirjoittaa levylle vain ja ainoastaan lokia?
Mutta varmaan jo olit sen näin tehnytkin =)
Tälläpä tavalla teen sen nyt. Sama pasteta tänne, kun kerran ei ole kuin harjoitusprojekti. Onpa muuten karmean näköistä koodia :)
Public Shared Function g_strHaeSaatiedot() As String
' Funktio mikä hakee ilmatieteenlaitoksen sivuilta säätiedot
' parsii hatutu tiedot järkevään muotoon ja palauttaa parsitun, selkokielisen tuloksen
' jatkossa tehdään valinta, että voi valita minkä paikan sää haetaan
' luodaan webbiclientti joka hakee sivuilta tauhkan
' luodaan steami johon tauhka luetaan
' luodaan streamreader
Dim wWebClient As New WebClient
Dim sStream As Stream
Dim srReader As StreamReader
Dim strParsi As String
' muuttujat joihin haetaan kaikki kolme riviä millä säätiedot ovat
Dim strHavaintoPaikka As String
Dim strHavaintoAika As String
Dim strHavaintoTemp As String
' parsimista varten omat muuttujat
Dim strPaikka As String
Dim strAika As String
Dim strLampotila As String
Dim strPaine As String
Dim strKosteus As String
Dim strTuuli As String
Dim strPilevet As String
Dim i As Integer
Try
' luetaan striimiin ilmatieteenlaitoksen lappeenrannan lähde
sStream = wWebClient.OpenRead("http://www.ilmatieteenlaitos. fi/saa/paikalli.html?kunta=Lappeenranta")
' alustetaan streamreaderi ja passataan haettu streami siihen
srReader = New StreamReader(sStream)
' luetana eka rivi, että ei ois nothing heti silmukan alussa
strParsi = srReader.ReadLine
' pyöritään silmukassa niin kauan että streami on luettu läpi
Do Until strParsi Is Nothing
' luetaan rivi ja siirrytään samalla seuraavaan
strParsi = srReader.ReadLine
' kasvatetaan rivilaskuria yhdellä
i = i + 1
' jos rivi on 113, niin luetaan kolme seuraavaa riviä. ko. riveill esiintyy kaikki tarvittavat tiedot
If i = 113 Then
strHavaintoPaikka = srReader.ReadLine
strHavaintoAika = srReader.ReadLine
strHavaintoTemp = srReader.ReadLine
' kaikki tarvittavat on nyt tiedossa
exit do
End If
Loop
' parsitaan tiedot
strPaikka = (m_strParsiPaikka(strHavaintoPaikka))
strAika = m_strParsiAika(strHavaintoAika)
strLampotila = m_strParsiTemp(strHavaintoTemp)
strPaine = m_strParsiPaine(strHavaintoTemp)
strKosteus = m_strParsiKosteus(strHavaintoTemp)
strTuuli = m_strParsiTuuli(strHavaintoTemp)
strPilevet = m_strParsiPilvet(strHavaintoTemp)
' palautetaan parsittu tauhka
g_strHaeSaatiedot = strPaikka & vbCrLf & strAika & vbCrLf & strLampotila & vbCrLf & strPaine & vbCrLf & strKosteus & vbCrLf & strTuuli & vbCrLf & strPilevet
Catch ex As Exception
' ilmotetaan virheestä
MsgBox("Error: " & ex.Message)
Finally
' tapetaan streami, webclientti ja readeri
sStream.Close()
wWebClient.Dispose()
srReader.Close()
End Try
End FunctionEli tuo funktio hakee halutun sivun streamiin ja parsii sen, palauttaa sitten stringin, jossa on parsitut tulokset. Tiedostoon kirjoittaminen tapahtuu vielä myöhemmin. Tuota pitää kyllä parannella vielä todella paljon ennen kuin sen siirtää sinne servicen puolelle. Pitää tehdä tarkistukset, että mitä tehdään jos sääpalvelu ei vastaakaan jne. Tällä hetkellä tuokin funktio on siis vielä sääkikkareeni käyttöliittymän puolella, mutta siirrän sen palveluun kun se on valmis. Sen palvelun on tarkoitus hakea vielä sääkartta ja viiden päivän ennsute kerran päivässä, nekin on jo tehty, mutta samat tarkistukset tulee vielä niihinkin.
Kertokaapa ideoita miten tarkistetaan tuon sivuston tila mistä haetaan tauhka. Eli ensin pitäisi ko. sivu pollata ja katosoa vastaako se. Jos ei vastaa niin odottaa tietty aika ja pollata uudelleen. Liekkö tuolla webclientillä mitään .seek -ominaisuutta joka sitten palauttaisi pollttavan sivun statuksen?
Esakom: eli juurihan niin minä sen olin tehnytkin =)
Aihe on jo aika vanha, joten et voi enää vastata siihen.