2009-09-11 14 views
16

W języku C#/.NET (w systemie Windows) jest sposób na odczyt "rosnącego" pliku przy użyciu strumienia plików? Długość pliku będzie bardzo mała, gdy strumień pliku zostanie otwarty, ale plik zostanie zapisany do innego wątku. Jeśli/kiedy strumień plików "dogoni" do drugiego wątku (tj. Gdy Read() zwraca 0 bajtów do odczytu), chcę wstrzymać, aby plik buforował nieco, a następnie kontynuować czytanie.Czytanie z rosnącego pliku w C#?

Naprawdę nie chcę używać FilesystemWatcher i nadal tworzyć nowe strumienie plików (jak sugerowano w przypadku plików dziennika), ponieważ nie jest to plik dziennika (jest to plik wideo zakodowany w locie) i wydajność jest problemem.

Dzięki
Robert

+0

zaktualizowałem moją odpowiedź. –

Odpowiedz

6

Możesz to zrobić, ale musisz uważnie śledzić pozycje odczytu i zapisu plików, używając Stream.Seek i odpowiedniej synchronizacji między wątkami. Zazwyczaj użyjesz EventWaitHandle lub jego podklasy do synchronizacji danych, a także będziesz musiał rozważyć synchronizację dostępu do samego obiektu FileStream (prawdopodobnie za pośrednictwem instrukcji lock).

Aktualizacja: Odpowiadając this question I wdrożone coś podobnego - sytuację, w której plik był pobierany w tle, a także są przesyłane w tym samym czasie. Użyłem buforów pamięci i opublikowałem gist, który ma działający kod. (To jest GPL, ale to może nie mieć znaczenia dla ciebie - w każdym razie możesz użyć zasad, by zrobić coś własnego.)

+0

Zajmę się tym ... dla kopnięć, czy łatwiej byłoby po prostu zapisać wynik kodowania w pamięci (np. Przy użyciu podwójnego bufora), a następnie wysłać go do pliku sieciowego i pamięci podręcznej w tym samym czasie? –

4

The Way I rozwiązać to za pomocą klasy DirectoryWatcher/FileSystemWatcher, a gdy uruchamia się na plik, który chcesz otworzyć FileStream i czytać do końca. A kiedy im zrobię czytanie, zapiszę pozycję czytnika, więc następnym razem, gdy uruchomi się DirectoryWatcher/FilesystemWatcher, otworzę strumień, ustawiając położenie w miejscu, w którym byłem ostatnim razem.

Wywołanie FileStream.length jest bardzo powolne, nie miałem żadnych problemów z wydajnością z moim rozwiązaniem (byłem im czytając "log" od 10mb do 50 ish).

Dla mnie rozwiązanie, które opisuję jest bardzo proste i łatwe w obsłudze, chciałbym go wypróbować i profilować. Nie sądzę, żeby na twoim komputerze pojawiały się problemy z wydajnością. Robię to, gdy ppl gra w grę wielowątkową, zabierając cały procesor i nikt nie skarżył się, że mój parser jest bardziej wymagający niż konkurencyjne parsery.

+1

Pytanie dotyczy specjalnych rabatów przy użyciu obserwatora, ze względu na obawy dotyczące wydajności. –

+0

Tak, zauważyłem. dodał więcej do mojej odpowiedzi dotyczącej wstępnej realizacji. – EKS

+0

Nie musisz koniecznie wywoływać FileStream.Length w czytniku, jeśli wszystko, co robisz, to czytanie tak daleko, jak to możliwe, a następnie czekanie na więcej danych. Jaki rodzaj opóźnienia widzisz, gdy uruchamiasz obserwatora? Czy to się zmienia w zależności od obciążenia maszyny? –

2

Jeszcze jedna rzecz, która może być przydatna to klasa FileStream ma właściwość o nazwie ReadTimeOut która jest zdefiniowane jako:

Pobiera lub ustawia wartość w milisekundach, która określa, jak długo strumień będzie próbował odczytać przed przekroczeniem limitu czasu. (dziedziczony ze strumienia)

Może to być użyteczne, ponieważ gdy twoje odczyty dorównają twojemu zapisowi, wątek wykonujący odczyty może zostać wstrzymany, gdy bufor zapisu zostanie przepłukany. Byłoby warto napisać mały test, aby sprawdzić, czy ta właściwość w jakikolwiek sposób pomoże twojej sprawie.

Czy operacje odczytu i zapisu mają miejsce w tym samym obiekcie? Jeśli tak, możesz napisać własne abstrakcje do pliku, a następnie napisać kod komunikatów z krzyżowymi wątkami, taki jak wątek, który wykonuje zapis i powiadomić wątek wykonujący odczyty, gdy zostanie zrobiony, aby wątek wykonujący odczyt wiedział, kiedy przerwać czytanie kiedy osiągnie EOF.

+0

W jaki sposób ta odpowiedź może uzyskać +3, jeśli ustawienie parametru ReadTimeOut w pliku FileStream spowoduje zgłoszenie wyjątku? : S –

4

ten pracował z StreamReader wokół pliku, z następujących etapów:

  1. w programie, która zapisuje do pliku, otworzyć go z dzielenia odczytu, tak:

    var out = new StreamWriter(File.Open("logFile.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)); 
    
  2. W programie, który odczytuje plik, otwórz go z dzielenia odczytu i zapisu, tak:

    using (FileStream fileStream = File.Open("logFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
    using (var file = new StreamReader(fileStream)) 
    
  3. Przed uzyskaniem dostępu do strumienia wejściowego sprawdź, czy koniec został osiągnięty, a jeśli tak, odczekaj chwilę.

    while (file.EndOfStream) 
    { 
        Thread.Sleep(5); 
    }