J'ai besoin d'écrire un test unitaire pour une méthode prenant un flux qui provient d'un fichier texte. Je voudrais faire quelque chose comme ça:
Stream s = GenerateStreamFromString("a,b \n c,d");
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;
}
N'oubliez pas d'utiliser Using:
using (var stream = GenerateStreamFromString("a,b \n c,d"))
{
// ... Do stuff to stream
}
À propos de la StreamWriter
non éliminée. StreamWriter
est simplement un wrapper autour du flux de base et n'utilise pas de ressources devant être éliminées. La méthode Dispose
ferme le sous-jacent Stream
auquel StreamWriter
écrit. Dans ce cas, c’est la MemoryStream
à renvoyer.
Dans .NET 4.5, il existe maintenant une surcharge pour StreamWriter
qui maintient le flux sous-jacent ouvert après la suppression de l'enregistreur, mais ce code fait la même chose et fonctionne également avec d'autres versions de .NET.
Voir Est-il possible de fermer un StreamWriter sans fermer son BaseStream?
Une autre solution:
public static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}
Ajoutez ceci à une classe d'utilitaire de chaîne statique:
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;
}
Cela ajoute une fonction d’extension pour que vous puissiez simplement:
using (var stringStream = "My string".ToStream())
{
// use stringStream
}
public Stream GenerateStreamFromString(string s)
{
return new MemoryStream(Encoding.UTF8.GetBytes(s));
}
Utilisez la classe MemoryStream
en appelant Encoding.GetBytes
pour convertir votre chaîne en tableau d’octets.
Avez-vous besoin par la suite d'une TextReader
sur le flux? Si tel est le cas, vous pouvez fournir directement une StringReader
et contourner les étapes MemoryStream
et Encoding
.
J'ai utilisé un mélange de réponses comme ceci:
public static Stream ToStream(this string str, Encoding enc = null)
{
enc = enc ?? Encoding.UTF8;
return new MemoryStream(enc.GetBytes(str ?? ""));
}
Et puis je l'utilise comme ça:
String someStr="This is a Test";
Encoding enc = getEncodingFromSomeWhere();
using (Stream stream = someStr.ToStream(enc))
{
// Do something with the stream....
}
Voici:
private Stream GenerateStreamFromString(String p)
{
Byte[] bytes = UTF8Encoding.GetBytes(p);
MemoryStream strm = new MemoryStream();
strm.Write(bytes, 0, bytes.Length);
return strm;
}
Nous utilisons les méthodes d'extension listées ci-dessous. Je pense que vous devriez faire en sorte que le développeur prenne une décision concernant l'encodage, afin qu'il y ait moins de magie.
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 ?? ""));
}
}
Version modernisée et légèrement modifiée des méthodes d'extension pour 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));
Modification comme suggéré dans le commentaire de @ Palec sur la réponse de Shaun Bowe.
Je pense que vous pouvez tirer parti de l’utilisation de MemoryStream . Vous pouvez le remplir avec les octets de chaîne que vous obtenez en utilisant la méthode GetBytes de Classe de codage .
Si vous devez modifier l'encodage, je vote pour la solution de @ ShaunBowe . Mais chaque réponse ici copie la chaîne entière en mémoire au moins une fois. Les réponses avec la combinaison ToCharArray
+ BlockCopy
le font deux fois.
Si cela compte, voici un simple wrapper Stream
pour la chaîne brute UTF-16. Si utilisé avec un StreamReader
sélectionnez Encoding.Unicode
pour cela:
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; // ;)
}
Et ici est une solution plus complète avec les contrôles liés nécessaires (dérivée de MemoryStream
et donc des méthodes ToArray
et WriteTo
.).