2013-02-10 10 views
6

Próbuję rozróżnić pliki "tekstowe" i "binarne", ponieważ bardzo chciałbym zignorować pliki z "nieczytelnymi" treściami.Oryginalne bajty plików z StreamReadera, wykrywanie numerów magicznych

Mam plik, który moim zdaniem jest archiwum GZIP. Próbuję zignorować tego rodzaju plik, wykrywając magiczne liczby/podpis pliku. Jeśli otworzę plik za pomocą wtyczki edytora heksadecymalnego w Notatniku ++, widzę pierwsze trzy kody szesnastkowe: 1f 8b 08.

Jednak jeśli czytam plik za pomocą StreamReader, nie jestem pewien, w jaki sposób dostać się do oryginalnych bajtów ..

using (var streamReader = new StreamReader(@"C:\file")) 
{ 
    char[] buffer = new char[10]; 
    streamReader.Read(buffer, 0, 10); 
    var s = new String(buffer); 

    byte[] bytes = new byte[6]; 
    System.Buffer.BlockCopy(s.ToCharArray(), 0, bytes, 0, 6); 
    var hex = BitConverter.ToString(bytes); 

    var otherhex = BitConverter.ToString(System.Text.Encoding.UTF8.GetBytes(s.ToCharArray())); 
} 

Pod koniec użyciu instrukcji Mam następujące wartości zmiennych:

hex: "1F-00-FD-FF-08-00" 
otherhex: "1F-EF-BF-BD-08-00-EF-BF-BD-EF-BF-BD-0A-51-02-03" 

Żadna z nich nie zaczyna się od wartości szesnastkowych pokazanych w Notatniku ++.

Czy jest możliwe pobranie oryginalnych bajtów z wyniku odczytu pliku przez StreamReader?

+0

tylko przetestować bajtów w bajtach tablica, nie potrzebujesz całego ciągu znaków –

+0

Problem jest (pomimo powyższego przykładu) ly zacznij od napisu (o którym wiem, że został wyprodukowany przez StreamReadera) i miałem nadzieję, że nie będę musiał zmieniać sposobu dostarczania ciągu znaków. [Ta odpowiedź] (http://stackoverflow.com/a/10380166/62072) wydaje się wskazywać, że możliwe jest pobranie oryginalnych bajtów z ciągu znaków. Czego mi brakuje? –

+0

1F, który widzisz w swoim czytniku heksadecymalnym, jest 31 przekonwertowany na 49 (x31) ("1") i 70 (x46) "F" Char (x1f) jest w ASCII, znak US (separator jednostek) jest niedrukowalny jak esc lub dzwonek. więc jeśli szukasz bajtów po skutecznej konwersji na znaki, musisz poszukać Char (x1f) Char (8B) char (8) –

Odpowiedz

5

Twój kod próbuje zmienić bufor binarny na ciąg znaków. Łańcuchy są w Unicode w NET, więc dwa bajty są wymagane. Wynik jest nieco nieprzewidywalny, jak widać.

Wystarczy użyć BinaryReader i jego metody ReadBytes

using(FileStream fs = new FileStream(@"C:\file", FileMode.Open, FileAccess.Read)) 
{ 
    using (var reader = new BinaryReader(fs, new ASCIIEncoding())) 
    { 
     byte[] buffer = new byte[10]; 
     buffer = reader.ReadBytes(10); 
     if(buffer[0] == 31 && buffer[1] == 139 && buffer[2] == 8) 
      // you have a signature match.... 
    } 
} 
2

Nie możesz. StreamReader służy do czytania tekstu, a nie binarnego. Użyj Stream bezpośrednio, aby przeczytać bajty. W twoim przypadku FileStream.

Aby odgadnąć, czy plik jest tekstowy, czy też binarny, można odczytać pierwsze 4K w postaci byte[] i zinterpretować to.

Przy okazji próbowałeś zmusić znaki do bajtów. Jest to nieważne z zasady. Sugeruję zapoznanie się z tym, czym jest Encoding: jest to tylko sposób konwersji między znakami i bajtami w semantycznie prawidłowy sposób.

2

użytkowania (do pliku PDF):

Assert.AreEqual("25504446", GetMagicNumbers(filePath, 4)); 

Method GetMagicNumbers:

private static string GetMagicNumbers(string filepath, int bytesCount) 
{ 
    // https://en.wikipedia.org/wiki/List_of_file_signatures 

    byte[] buffer; 
    using (var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read)) 
    using (var reader = new BinaryReader(fs)) 
     buffer = reader.ReadBytes(bytesCount); 

    var hex = BitConverter.ToString(buffer); 
    return hex.Replace("-", String.Empty).ToLower(); 
} 
Powiązane problemy