什么是Stream?
流就是提供字节序列的一般视图
(也有人理解的流是向自然界的河流那样清澈而又美丽,c#中的流也是一样,许多技术或者说核心技术都需要流的帮忙)
什么是字节序列呢?
其实字节序列就是字节对象都被存储为连续的字节序列,字节按照一定的顺序进行排序组成了字节序列
(形象得理解为:一条河中有一条鱼游过,这个鱼就是一个字节,这个字节包括鱼的眼睛,嘴巴,等组成8个二进制,显然这条河就是我们的核心对象:流)
Stream是如何使用的
Stream 类有一个protected 类型的构造函数, 但是它是个抽象类,无法直接如下使用
- CanRead: 只读属性,判断该流是否能够读取
- CanSeek: 只读属性,判断该流是否支持跟踪查找
- CanWrite: 只读属性,判断当前流是否可写
- Flush方法比较重要:
当我们使用流写文件时,数据流会先进入到缓冲区中,而不会立刻写入文件,当执行这个方法后,缓冲区的数据流会立即注入基础流。MSDN中的描述:使用此方法将所有信息从基础缓冲区移动到其目标或清除缓冲区,或者同时执行这两种操作。根据对象的状态,可能需要修改流内的当前位置(例如:在基础流支持查找的情况下即如此)当使StreamWriter 或 BinaryWriter 类时,不要刷新 Stream 基对象。而应使用该类的 Flush 或 Close 方法,此方法确保首先将该数据刷新至基础流,然后再将其写入文件 - Length:表示流的长度
- Position属性(非常重要):
虽然从字面中可以看出这个Position属性只是标示了流中的一个位置而已,很多asp.net项目中文件或图片上传中很多朋友会经历过这样一个痛苦:Stream对象被缓存了,导致了Position属性在流中无法找到正确的位置,这点会让人抓狂,其实解决这个问题很简单,聪明的你肯定想到了,其实我们每次使用流前必须将Stream.Position设置成0就行了,但是这还不能根本上解决问题,最好的方法就是用Using语句将流对象包裹起来,用完后关闭回收即可 - abstract int Read(byte[] buffer, int offset, int count)方法:
这个方法包含了3个关键的参数:缓冲字节数组,位移偏量和读取字节个数,每次读取一个字节后会返回一个缓冲区中的总字节数
第一个参数:这个数组相当于一个空盒子,Read()方法每次读取流中的一个字节将其放进这个空盒子中。(全部读完后便可使用buffer字节数组了)
第二个参数:表示位移偏量,告诉我们从流中哪个位置(偏移量)开始读取。
最后一个参数:就是读取多少字节数。
返回值便是总共读取了多少字节数. - abstract long Seek(long offset, SeekOrigin origin)方法:
其实Seek方法就是重新设定流中的一个位置,在说明offset参数作用之前大家先来了解下SeekOrigin这个枚举:
如果 offset 为负,则要求新位置位于 origin 指定的位置之前,其间隔相差 offset 指定的字节数。如果 offset 为零 (0),则要求新位置位于由 origin 指定的位置处
如果 offset 为正,则要求新位置位于 origin 指定的位置之后,其间隔相差 offset 指定的字节数.
Stream. Seek(-3,Origin.End); 表示在流末端往前数第3个位置
Stream. Seek(0,Origin.Begin); 表示在流的开头位置
Stream. Seek(3,Orig`in.Current); 表示在流的当前位置往后数第三个位置
查找之后会返回一个流中的一个新位置 - abstract void Write(byte[] buffer,int offset,int count):
这个方法包含了3个关键的参数:缓冲字节数组,位移偏量和读取字节个数和read方法不同的是 write方法中的第一个参数buffer已经有了许多byte类型的数据,我们只需通过设置 offset和count来将buffer中的数据写入流中 - virtual void Close():
关闭流并释放资源,在实际操作中,如果不用using的话,别忘了使用完流之后将其关闭;这个方法特别重要,使用完当前流千万别忘记关闭
其它类型流简单的使用
FileStream
/// <summary>
/// 用FileStream1直接写入数据
/// </summary>
static void GetFileStream2()
{
string content = @"<?xml version='1.0' encoding='utf-8'?>
<TAS>
<szUTCDate>20200807085759</szUTCDate>
<szTaDomain>POS</szTaDomain>
<szTaType>SA</szTaType>
<szTaOperationType>SALE</szTaOperationType>
<szInfo>0</szInfo>
<bNotPrinted>-1</bNotPrinted>
<lClientID>1</lClientID>
<szExternalClientID>CN</szExternalClientID>
<szClientName>CHINA</szClientName>
<szMode>POSMODE</szMode>
<szSessionID>6190:2:11343:2:20200807</szSessionID>
<szFooterLine1>HAVE A NICE DAY – 祝您购物愉快</szFooterLine1>
<szFooterLine2>美丽购物新捷径</szFooterLine2>
<szFooterLine3>退货规定</szFooterLine3>
<szFooterLine4>所有护肤,彩妆,香水产品, 一经售出,不予退换,过敏问题除外。</szFooterLine4>
<szFooterLine5>2.如使用产品过敏,请凭制定医院证明及原始购物小票办理退货,因化妆品有一定的使</szFooterLine5>
<szFooterLine6 Type='202'>3.门店不接受非本店售出商品的退换货。</szFooterLine6>
< szFooterLine7 Type = '202'> 4.商品退货时需退回相应的赠品,如赠品不能退回将酌情扣除部分退货金额。</ szFooterLine7 >
</ TAS > ";
string FilePath = @"E:\开发学习\流的认知\File\test.txt";
FileStream sterm = new FileStream(FilePath, FileMode.Truncate, FileAccess.Write);
byte[] byData = Encoding.UTF8.GetBytes(content); //建立一个FileStream要用的字节组
sterm.Seek(10095, SeekOrigin.Begin); //指定从那个字节读数据
sterm.Write(byData,0, byData.Length);
sterm.Close();
sterm.Dispose();
}
/// <summary>
/// 用FileStream1直接读取数据
/// </summary>
static void GetFileStream1()
{
string FilePath = @"E:\开发学习\流的认知\File\66619000200113962020080716543620200807085900.txt";
FileStream sterm = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Read);
byte[] byData = new byte[sterm.Length]; //建立一个FileStream要用的字节组
sterm.Seek(0, SeekOrigin.Begin); //指定从那个字节读数据
sterm.Read(byData, 0, byData.Length);
#region 方法1.将字节组直接转换成utf8字符组
//char[] charData = new char[byData.Length]; //建立一个字符组
//Decoder d = Encoding.UTF8.GetDecoder();
//d.GetChars(byData, 0, byData.Length, charData, 0); //将编码字节数组转换为字符数组
#endregion
#region 方法2.直接将字节组转换成utf8字符组
string charData = Encoding.UTF8.GetString(byData);
#endregion
Console.WriteLine(charData);
sterm.Close();
sterm.Dispose();
}
StreamReade、StreamWriter
/// <summary>
/// 用StreamWriter配合FileStream写入数据
/// </summary>
static void GetFileStream4()
{
string content = @"<?xml version='1.0' encoding='utf-8'?>
<TAS>
<szUTCDate>20200807085759</szUTCDate>
<szTaDomain>POS</szTaDomain>
<szTaType>SA</szTaType>
<szTaOperationType>SALE</szTaOperationType>
<szInfo>0</szInfo>
<bNotPrinted>-1</bNotPrinted>
<lClientID>1</lClientID>
<szExternalClientID>CN</szExternalClientID>
<szClientName>CHINA</szClientName>
<szMode>POSMODE</szMode>
<szSessionID>6190:2:11343:2:20200807</szSessionID>
<szFooterLine1>HAVE A NICE DAY – 祝您购物愉快</szFooterLine1>
<szFooterLine2>美丽购物新捷径</szFooterLine2>
<szFooterLine3>退货规定</szFooterLine3>
<szFooterLine4>所有护肤,彩妆,香水产品, 一经售出,不予退换,过敏问题除外。</szFooterLine4>
<szFooterLine5>2.如使用产品过敏,请凭制定医院证明及原始购物小票办理退货,因化妆品有一定的使</szFooterLine5>
<szFooterLine6 Type='202'>3.门店不接受非本店售出商品的退换货。</szFooterLine6>
< szFooterLine7 Type = '202'> 4.商品退货时需退回相应的赠品,如赠品不能退回将酌情扣除部分退货金额。</ szFooterLine7 >
</ TAS > ";
string FilePath = @"E:\开发学习\流的认知\File\test.txt";
FileStream sterm = new FileStream(FilePath, FileMode.Truncate);
StreamWriter sw = new StreamWriter(sterm);
sw.Write(content);
sw.Close();
sw.Dispose();
sterm.Close();
sterm.Dispose();
}
/// <summary>
/// 用StreamReader配合FileStream读取数据
/// </summary>
static void GetFileStream3()
{
string FilePath = @"E:\开发学习\流的认知\File\66619000200113962020080716543620200807085900.txt";
FileStream sterm = new FileStream(FilePath, FileMode.Open);
StreamReader sr = new StreamReader(sterm);
#region 直接读取所有数据
Console.WriteLine(sr.ReadToEnd());
#endregion
#region 一行一行的读取
//string read = null;
//while ((read = sr.ReadLine()) != null)
//{
// Console.WriteLine(read);
//}
#endregion
sr.Close();
sr.Dispose();
}
MemoryStream
/// <summary>
/// 用MemoryStream1写入数据
/// </summary>
static void GetMemoryStream1()
{
string content = @"<?xml version='1.0' encoding='utf-8'?>
<TAS>
<szUTCDate>20200807085759</szUTCDate>
<szTaDomain>POS</szTaDomain>
<szTaType>SA</szTaType>
<szTaOperationType>SALE</szTaOperationType>
<szInfo>0</szInfo>
<bNotPrinted>-1</bNotPrinted>
<lClientID>1</lClientID>
<szExternalClientID>CN</szExternalClientID>
<szClientName>CHINA</szClientName>
<szMode>POSMODE</szMode>
<szSessionID>6190:2:11343:2:20200807</szSessionID>
<szFooterLine1>HAVE A NICE DAY – 祝您购物愉快</szFooterLine1>
<szFooterLine2>美丽购物新捷径</szFooterLine2>
<szFooterLine3>退货规定</szFooterLine3>
<szFooterLine4>所有护肤,彩妆,香水产品, 一经售出,不予退换,过敏问题除外。</szFooterLine4>
<szFooterLine5>2.如使用产品过敏,请凭制定医院证明及原始购物小票办理退货,因化妆品有一定的使</szFooterLine5>
<szFooterLine6 Type='202'>3.门店不接受非本店售出商品的退换货。</szFooterLine6>
< szFooterLine7 Type = '202'> 4.商品退货时需退回相应的赠品,如赠品不能退回将酌情扣除部分退货金额。</ szFooterLine7 >
</ TAS > ";
MemoryStream memory = new MemoryStream();
byte[] array = Encoding.UTF8.GetBytes(content);//将字符串转化为字节数组
memory.Seek(5000,SeekOrigin.Begin);
memory.Write(array,0, array.Length);
byte[] arrayNew = memory.ToArray();//将内存中的数据转换为字节数组
string strNew = Encoding.UTF8.GetString(arrayNew);//将字节数组转换为字符串
Console.WriteLine(strNew);
memory.Close();
memory.Dispose();
//byte[] array = Encoding.UTF8.GetBytes(content);//将字符串转化为字节数组
//MemoryStream memory = new MemoryStream(array);//初始化MemoryStream类
//byte[] arrayNew = memory.ToArray();//将内存中的数据转换为字节数组
//string strNew = Encoding.UTF8.GetString(arrayNew);//将字节数组转换为字符串
//Console.WriteLine(strNew);
//memory.Close();
//memory.Dispose();
}