2012-05-04 11 views
31

Próbuję napisać obiekt do łańcucha Xml i pobrać ten ciąg i zapisać go do bazy danych. Ale najpierw muszę uzyskać ciąg ...Odczytywanie ze strumienia pamięci do ciągu znaków

private static readonly Encoding LocalEncoding = Encoding.UTF8; 

    public static string SaveToString<T> (T settings) 
    { 
     Stream stream = null; 
     TextWriter writer = null; 
     string settingsString = null; 

     try 
     { 
      stream = new MemoryStream(); 

      var serializer = new XmlSerializer(typeof(T)); 

      writer = new StreamWriter(stream, LocalEncoding); 

      serializer.Serialize(writer, settings); 

      var buffer = new byte[stream.Length]; 

      stream.Read(buffer, 0, (int)stream.Length); 

      settingsString = LocalEncoding.GetString(buffer); 
     } 
     catch(Exception ex) 
     { 
      // If the action cancels we don't want to throw, just return null. 
     } 
     finally 
     { 
      if (stream != null) 
       stream.Close(); 

      if(writer != null) 
       writer.Close(); 
     } 

     return settingsString; 
    } 

To wydaje się działać, strumień jest wypełniony bajtami. Ale kiedy przychodzę do odczytu z powrotem do bufora, a następnie do łańcucha ... bufor jest wypełniony "0"! Nie jestem pewien, co robię źle tutaj.

+1

możliwe duplikat [Jak uzyskać ciąg z MemoryStream?] (Http://stackoverflow.com/questions/78181/how-do-you-get-a-string-from -a-memorystream) – andyp

Odpowiedz

64

Jeśli sprawdzisz wyniki stream.Read, zobaczysz, że nic nie przeczytałeś - ponieważ nie przewinąłeś strumienia. (Można to zrobić z stream.Position = 0;). Jednak łatwiej jest po prostu zadzwoń ToArray:

settingsString = LocalEncoding.GetString(stream.ToArray()); 

(Musisz zmienić typ stream z Stream do MemoryStream, ale to jest w porządku, jak to jest w ten sam sposób gdzie go tworzysz.)

Alternatywnie - a nawet bardziej prosto - po prostu użyj StringWriter zamiast StreamWriter. Musisz utworzyć podklasę, jeśli chcesz używać UTF-8 zamiast UTF-16, ale to całkiem proste. Zobacz przykład this answer.

Jestem zaniepokojony tym, że po prostu łapiesz Exception i , zakładając, że oznacza to coś nieszkodliwego, przy okazji - nawet nie rejestrując niczego. Zauważ, że instrukcje using są generalnie czystsze niż pisanie jawnych bloków.

+0

Dzięki :). To szybka robota. Wiem, że bloki używane są bardziej popularne. Ale podoba mi się płaskość, jaką mi to daje, żadnych zagnieżdżonych rzeczy. Co jest tylko stylem. Nie wiedziałem, że istnieje StringWriter, wydaje się znacznie łatwiejsze, ale lubię możliwość określenia encoing. Prawdopodobnie dodam do tego przeciążenie, a nie nową klasę. – tigerswithguitars

+0

@tigerswithgitars: Jak dokładnie zamierzasz dodać przeciążenie do samego StringWriter? Punkt nowej klasy jest taki, że 'StringWriter' zawsze zwraca kodowanie UTF-16 z jego własności' TextWriter.Encoding'; dodatkowa klasa po prostu przesłania tę właściwość. –

+0

Przepraszam, moje sformułowanie było mylące. Dodam przeciążenie do mojej własnej metody, aby określić kodowanie. – tigerswithguitars

8
string result = System.Text.Encoding.UTF8.GetString(fs.ToArray()); 
+1

Podczas gdy ta próbka kodu może w końcu odpowiedzieć na pytanie, byłoby wskazane, aby podać tutaj podstawowe wyjaśnienie. –

+0

Co to jest "rdzeń" tutaj? Jeśli zmienna, jak ją utworzyłeś? To samo pytanie dla 'fs'. –

+0

Użytkownik błędnie używał pnia zamiast Systemu – Prasanth

1
string result = Encoding.UTF8.GetString((stream as MemoryStream).ToArray()); 
+0

. Zapytałbym o użycie słowa "as" tutaj - nie chroni cię przed niczym. Po pierwsze, wiesz, że strumień jest mimo wszystko 'MemoryStream', a nawet, jeśli nie był, przekazanie' null' do 'GetString' rzuci wyjątek, więc równie dobrze możesz użyć jawnej obsady. –

+1

Chociaż ten kod może odpowiedzieć na pytanie, podanie dodatkowego kontekstu dotyczącego tego, dlaczego i/lub jak ten kod odpowiada na pytanie, poprawia jego długoterminową wartość. – ryanyuyu