Запись строки в поток и ее чтение не работает - PullRequest
36 голосов
/ 13 апреля 2010

Я хочу записать строку в поток (в данном случае MemoryStream) и прочитать байты один за другим.

stringAsStream = new MemoryStream();
UnicodeEncoding uniEncoding = new UnicodeEncoding();
String message = "Message";

stringAsStream.Write(uniEncoding.GetBytes(message), 0, message.Length);

Console.WriteLine("This:\t\t" + (char)uniEncoding.GetBytes(message)[0]);
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte());

(Нежелательный) результат, который я получаю:

This:         M
Differs from: ?

Это выглядит как будто оно не читается правильно, так как первый символ «Message» - это «M», который работает при получении байтов из экземпляра UnicodeEncoding, но не при чтении их из потока .

Что я делаю не так?


Более общая картина: у меня есть алгоритм, который будет работать с байтами потока, я хотел бы быть как можно более общим и работать с любым потоком. Я хотел бы преобразовать ASCII-строку в MemoryStream или, возможно, использовать другой метод, чтобы иметь возможность работать со строкой как поток. Данный алгоритм будет работать с байтами потока.

Ответы [ 5 ]

61 голосов
/ 13 апреля 2010

После того, как вы написали в MemoryStream и перед тем, как читать его обратно, вам нужно Seek вернуться к началу MemoryStream, чтобы вы не читали с конца.

ОБНОВЛЕНИЕ

После просмотра вашего обновления я думаю, что есть более надежный способ создания потока:

UnicodeEncoding uniEncoding = new UnicodeEncoding();
String message = "Message";

// You might not want to use the outer using statement that I have
// I wasn't sure how long you would need the MemoryStream object    
using(MemoryStream ms = new MemoryStream())
{
    var sw = new StreamWriter(ms, uniEncoding);
    try
    {
        sw.Write(message);
        sw.Flush();//otherwise you are risking empty stream
        ms.Seek(0, SeekOrigin.Begin);

        // Test and work with the stream here. 
        // If you need to start back at the beginning, be sure to Seek again.
    }
    finally
    {
        sw.Dispose();
    }
}

Как видите, этот код использует StreamWriter для записився строка (с правильной кодировкой) до MemoryStream.Это устраняет необходимость записи всего байтового массива для строки.

Обновление: Я несколько раз сталкивался с проблемой пустого потока.Достаточно позвонить Flush сразу после того, как вы закончили писать.

34 голосов
/ 20 апреля 2012

Попробуйте этот «однострочный» из Блог Delta , String To MemoryStream (C #) .

MemoryStream stringInMemoryStream =
   new MemoryStream(ASCIIEncoding.Default.GetBytes("Your string here"));

Строка будет загружена в MemoryStream, и вы сможете прочитать из нее. См. Encoding.GetBytes (...) , который также был реализован для некоторых других кодировок .

14 голосов
/ 13 апреля 2010

Вы используете message.Length, который возвращает количество символов в строке, но вы должны использовать номер байтов для чтения. Вы должны использовать что-то вроде:

byte[] messageBytes = uniEncoding.GetBytes(message);
stringAsStream.Write(messageBytes, 0, messageBytes.Length);

Затем вы читаете один байт и ожидаете получить от него символ, просто приведя к char. UnicodeEncoding будет использовать два байта на символ.

Как говорит Джастин, вы также не пытаетесь вернуться к началу потока.

Вообще-то, я боюсь, что здесь все не так. Пожалуйста, дайте нам более широкую картину, и мы можем помочь вам решить, что вы должны действительно делать. Использование StreamWriter для записи, а затем StreamReader для чтения вполне возможно, что вы хотите, но мы не можем действительно отличить только небольшой фрагмент кода, который вы показали.

5 голосов
/ 13 апреля 2010

Я думаю, что было бы намного более продуктивно использовать TextWriter, в этом случае StreamWriter для записи в MemoryStream. После этого, как уже говорили другие, вам нужно «перемотать» MemoryStream, используя что-то вроде stringAsStream.Position = 0L;.

stringAsStream = new MemoryStream();

// create stream writer with UTF-16 (Unicode) encoding to write to the memory stream
using(StreamWriter sWriter = new StreamWriter(stringAsStream, UnicodeEncoding.Unicode))
{
  sWriter.Write("Lorem ipsum.");
}
stringAsStream.Position = 0L; // rewind

Обратите внимание, что:

StreamWriter по умолчанию использует экземпляр UTF8Encoding, если не указано иное. Этот экземпляр UTF8Encoding создается без метки порядка байтов (BOM)

Кроме того, вам обычно не нужно создавать new UnicodeEncoding(), поскольку он уже есть в качестве статического члена класса для использования в удобных вариантах utf-8, utf-16 и utf-32.

И затем, наконец (как уже говорили другие), вы пытаетесь преобразовать byte непосредственно в char с, а они - нет. Если бы у меня был поток памяти и я знал, что это строка, я бы использовал TextReader, чтобы получить строку из байтов. Мне кажется «опасным» возиться с необработанными байтами.

1 голос
/ 13 апреля 2010

Вам необходимо сбросить поток на начало:

stringAsStream.Seek(0, SeekOrigin.Begin);
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte());

Это также можно сделать, установив для свойства Position значение 0:

stringAsStream.Position = 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...