Bir dizeden nasıl akış oluştururum?


Yanıtlar:


956
public static Stream GenerateStreamFromString(string s)
{
    var stream = new MemoryStream();
    var writer = new StreamWriter(stream);
    writer.Write(s);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

Kullanmayı kullanmayı unutmayın:

using (var stream = GenerateStreamFromString("a,b \n c,d"))
{
    // ... Do stuff to stream
}

Bertaraf StreamWriteredilmeme hakkında. StreamWritertemel akışın etrafındaki bir pakettir ve atılması gereken kaynakları kullanmaz. DisposeYöntem yatan kapanacak Streamo StreamWriteryazıyor. Bu durumda MemoryStreamgeri dönmek istiyoruz.

.NET 4.5'te artık StreamWriteryazar atıldıktan sonra temel akışı açık tutan bir aşırı yükleme var , ancak bu kod aynı şeyi yapıyor ve .NET'in diğer sürümleriyle de çalışıyor.

Bkz. Bir StreamWriter'ı BaseStream öğesini kapatmadan kapatmanın bir yolu var mı?


134
Dikkat çekilmesi gereken önemli bir nokta, bir akışın bayttan, dize karakterlerden oluşmasıdır. Bir karakteri bir veya daha fazla bayta (veya bu durumda olduğu gibi bir Akışa) dönüştürmenin her zaman belirli bir kodlamayı kullandığını (veya varsayar) anlamak çok önemlidir . Bu yanıt, bazı durumlarda doğru olsa da, Varsayılan kodlamayı kullanır ve genel olarak uygun olmayabilir. Bir Kodlamanın StreamWriter yapıcısına açıkça geçirilmesi, yazarın Kodlama'nın sonuçlarını dikkate alması gerektiğini daha açık hale getirecektir.
drwatsoncode 28:14

6
Akışı kullanmak için "Kullanmayı kullanmayı unutma" diyorsunuz, ancak GenerateStreamFromStringyönteminizde, StreamWriter ile kullanma özelliğini kullanmıyorsunuz. Bunun bir sebebi var mı?
Ben

12
@Ben Evet. StreamWriter'ı atarsanız, temel akış da kapatılır. Biz bunu istemiyoruz. Yazarın tek kullanımlık olmasının tek nedeni akışı temizlemektir, bu nedenle yoksaymak güvenlidir.
Cameron MacFarland

2
Ayrıca, tüm dizenin büyük dizeler için önemli olabilecek bir belleğe kopyalandığına dikkat edilmelidir, çünkü şimdi bellekte bir ekstra kopya var.
UGEEN

1
@ahong Pek değil. StreamWritermuhtemelen dahili olarak söylediklerini yapıyor. Avantaj kapsülleme ve basit koddur, ancak kodlama gibi şeyleri soyutlama pahasına. Neyi başarmaya çalıştığınıza bağlıdır.
Cameron MacFarland

724

Başka bir çözüm:

public static MemoryStream GenerateStreamFromString(string value)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}

31
Birisi bunu bir XML dizisi serileştirme ile kullanırsa, ben bir bayrak olmadan çalışması için UTF8 Unicode geçmek zorunda kaldı. Büyük mesaj !!!
Gaspa79

2
Bunu (Rhyous'un verdiği ince ayar ve uzatma yöntemi olarak kullanmak için önemsiz ekstra şeker ile) kabul edilen cevaptan daha iyi seviyorum; daha esnek, daha az LOC ve daha az nesne dahil (StreamWriter için açık bir gereklilik yok)
KeithS

2
new MemoryStream(Encoding.UTF8.GetBytes("\ufeff" + (value ?? ""))Eğer ürün
ağacının

5
Bu çok kompakt bir sözdizimidir, ancak çok fazla bayt tahsisine neden olacaktır [], bu nedenle yüksek performans koduna dikkat edin.
michael.aird

1
Bu çözüm, akışı salt okunur yapma fırsatını hala bıraktı. new MemoryStream( value, false ). Bir akış yazarıyla yazmak zorunda kalırsanız bir akışı salt okunur yapamazsınız.
codekandis

106

Bunu statik dize yardımcı sınıfına ekleyin:

public static Stream ToStream(this string str)
{
    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(str);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

Bu, basitçe şunları yapabilmeniz için bir uzantı işlevi ekler:

using (var stringStream = "My string".ToStream())
{
    // use stringStream
}

5
Çöp toplayıcı temizlediğinde geri dönen akışın (yarı rastgele istisnalara neden olan) kapandığını keşfettim StreamWriter. Düzeltme, farklı bir yapıcı kullanmaktı - bir tanesi leaveOpen belirtmeme izin verdi .
Bevan

45
public Stream GenerateStreamFromString(string s)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(s));
}

24

İlk önce dizenizi bir bayt dizisine dönüştürmek için MemoryStreamçağrı Encoding.GetBytesyaparak sınıfı kullanın .

Daha sonra TextReaderakışta bir ihtiyacınız var mı? Eğer öyleyse, StringReaderdoğrudan bir tedarik edebilir ve MemoryStreamve Encodingadımlarını atlayabilirsiniz .


23

Bunun gibi cevapların bir karışımını kullandım:

public static Stream ToStream(this string str, Encoding enc = null)
{
    enc = enc ?? Encoding.UTF8;
    return new MemoryStream(enc.GetBytes(str ?? ""));
}

Ve sonra böyle kullanıyorum:

String someStr="This is a Test";
Encoding enc = getEncodingFromSomeWhere();
using (Stream stream = someStr.ToStream(enc))
{
    // Do something with the stream....
}

Thomas, niye oy vermedin? enc = enc ?? Encoding.UTF8 özel olarak belirli bir kodlama veya varsayılan UTF8 ile akış sormama izin veriyor ve .net'te (.net 4.0'ı kullandığım sürece) işlevde dize dışında bir başvuru türü veremezsiniz. Bu çizginin imzası gerekli, bu mantıklı mı?
Robocide

Bunu ayrı bir sınıfa (jenerik olmayan statik sınıf?) koymanız gerektiğini belirtmek de yararlıdır ve aşağı oyları azaltır.
Ali

13

Aşağıda listelenen uzantı yöntemlerini kullanıyoruz. Geliştiricinin kodlama hakkında bir karar vermesini sağlamanız gerektiğini düşünüyorum, bu yüzden daha az sihir var.

public static class StringExtensions {

    public static Stream ToStream(this string s) {
        return s.ToStream(Encoding.UTF8);
    }

    public static Stream ToStream(this string s, Encoding encoding) {
        return new MemoryStream(encoding.GetBytes(s ?? ""));
    }
}

1
İlk yöntemi olarak uygulamayı tercih ederim return ToStream(s, Encoding.UTF8);. Mevcut uygulamada ( return s.ToStream(Encoding.UTF8);, geliştirici kodu kavramak için daha fazla düşünmek zorunda kalıyor ve durumun ele s == nullNullReferenceException
alınmadığı

10

Hadi bakalım:

private Stream GenerateStreamFromString(String p)
{
    Byte[] bytes = UTF8Encoding.GetBytes(p);
    MemoryStream strm = new MemoryStream();
    strm.Write(bytes, 0, bytes.Length);
    return strm;
}

1
Yazmadan sonra konumun sıfırlanması gerekir. Joelnet cevabında olduğu gibi yapıcıyı kullanmak daha iyidir.
Jim Balter

10

Aşağıdakiler için uzantı yöntemlerinin modernize edilmiş ve biraz değiştirilmiş sürümü ToStream:

public static Stream ToStream(this string value) => ToStream(value, Encoding.UTF8);

public static Stream ToStream(this string value, Encoding encoding) 
                          => new MemoryStream(encoding.GetBytes(value ?? string.Empty));

@ Palec'in @Shaun Bowe yanıtı yorumunda önerildiği gibi değişiklik.



4

Kodlamayı değiştirmeniz gerekiyorsa @ShaunBowe'nin çözümü için oy kullanıyorum . Ancak buradaki her cevap, tüm dizeyi en az bir kez kopyalar. ToCharArray+ BlockCopyCombo ile verilen cevaplar iki kez yapılır.

Burada Streamönemliyse, ham UTF-16 dizesi için basit bir sarıcıdır. Bunun için bir StreamReaderseçim ile kullanılırsa Encoding.Unicode:

public class StringStream : Stream
{
    private readonly string str;

    public override bool CanRead => true;
    public override bool CanSeek => true;
    public override bool CanWrite => false;
    public override long Length => str.Length * 2;
    public override long Position { get; set; } // TODO: bounds check

    public StringStream(string s) => str = s ?? throw new ArgumentNullException(nameof(s));

    public override long Seek(long offset, SeekOrigin origin)
    {
        switch (origin)
        {
            case SeekOrigin.Begin:
                Position = offset;
                break;
            case SeekOrigin.Current:
                Position += offset;
                break;
            case SeekOrigin.End:
                Position = Length - offset;
                break;
        }

        return Position;
    }

    private byte this[int i] => (i & 1) == 0 ? (byte)(str[i / 2] & 0xFF) : (byte)(str[i / 2] >> 8);

    public override int Read(byte[] buffer, int offset, int count)
    {
        // TODO: bounds check
        var len = Math.Min(count, Length - Position);
        for (int i = 0; i < len; i++)
            buffer[offset++] = this[(int)(Position++)];
        return (int)len;
    }

    public override int ReadByte() => Position >= Length ? -1 : this[(int)Position++];
    public override void Flush() { }
    public override void SetLength(long value) => throw new NotSupportedException();
    public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
    public override string ToString() => str; // ;)     
}

Ve burada gerekli bağlı kontrollerle ( MemoryStreamsahip olduğu ToArrayve WriteToyöntemlerden de türetilmiş) daha eksiksiz bir çözüm .


-2

Dize uzantılarının iyi bir kombinasyonu:

public static byte[] GetBytes(this string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

public static Stream ToStream(this string str)
{
    Stream StringStream = new MemoryStream();
    StringStream.Read(str.GetBytes(), 0, str.Length);
    return StringStream;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.