Stream中提供了在流开始/末尾处写入文本的方法。如下实现一个在流的指定位置写入文本的方法。
例:在下面文本的某指定位置写入字符文本
实现原理
获取想要写入的文本位置,把该位置后的所有文本+写入文本复制到另一byte数组中,最后用该byte数组重写后面的部分即完成“指定写入”的操作。
代码实现
步骤一:创建Stream流对象,获取文本的信息
步骤二:指定我们要查找的文本位置(例在以上文本的“微软公司”前写入文本),流不能直接操作字符串,所以把该字符串转为byte数组存储。
步骤三:根据提供的byte数组返回其在文本中所对应的流位置
此方法的核心来自网络查找,有些许改动。
参数一表示要搜索的流;
参数二表示流搜索的开始位置,一般从0开始;
参数三表示需要搜索位置的关键字
参数四表示要查找的第几个关键字(比如一个文本中有多个此关键字)
返回值是该关键字所在的流位置,未找到时返回-1
步骤四: 从当前返回的流位置开始,获取后面所有的文本内容,并把内容存放在byte数组中
步骤五:创建我们想要写入该位置的字符串(在“微软公司”前面写入“测试”),并把该字符串转换的byte数组和上面的数组内容合并。 (这里我是先把上面的数组转换成了字符串,再将字符串合并后转为的数组,可能麻烦了一点)
步骤六:在该位置后重写新建的流,完成指定写入操作。(流写入时会直接替换掉后面已有的内容)
实现效果:
如果你想插入位置的关键字有多个同名,更改Search方法的最后一个参数查找指定次数后的关键字即可。如需要完成写入时类似回车的操作,字符串加对应的转义字符即可。
完整代码
class Program
{
static void Main(string[] args)
{
string path = "temp.txt";
using (Stream stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
//查找指定的字符
string findIndex = "微软公司";
//把当前查找字符转换成byte数组
byte[] byteIndex = MyStream.ToByteArray(findIndex);
//在当前文本流中查找第1次查找到的指定byte数组的流位置
//第二个参数是设置流开始查找的位置,默认从0开始。
//第四个次数是第index次查找到的关键字
long index = MyStream.Search(stream, 0, byteIndex, 1);
//如果index返回-1则表示没有找到这个匹配字符,跳出。
if (index == -1)
{
stream.Close();
return;
}
//根据查找到的位置,新建一个和返回值后面所有内容的数量一致的byte数组
byte[] bytes = new byte[stream.Length - index];
//把指针定位到当前查找到的流位置下,即让流从该位置开始查找
stream.Seek(index , SeekOrigin.Begin);
//根据流位置把剩余内容全部读取到新建的byte数组中
stream.Read(bytes, 0, bytes.Length);
//我们需要写入的字符
string text = "测试";
//新建一个新字符串,该字符串=自己写入的文本+索引后剩余的文本
string res = text + MyStream.ToStr(bytes);
//把该替换后的文本转化成byte数组保存
bytes = MyStream.ToByteArray(res);
//重新把指针定位到之前查找到的流位置下(因为read后指针位置会改变)
stream.Seek(index , SeekOrigin.Begin);
//写入重新整合后的文本,完成“替换”
stream.Write(bytes, 0, bytes.Length);
//释放流资源
stream.Close();
}
Console.ReadLine();
}
}
static class MyStream {
/// <summary>
/// byte数组转换为字符串
/// </summary>
/// <returns></returns>
public static string ToStr(this byte[] arr)
{
return System.Text.Encoding.Default.GetString(arr);
}
/// <summary>
/// 字符串转换成byte数组
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static byte[] ToByteArray(this string str)
{
return System.Text.Encoding.Default.GetBytes(str);
}
/// <summary>
/// 在当前流中搜索指定的 byte[]
/// </summary>
/// <param name="stream"></param>
/// <param name="beginPosition">搜索开始位置,从0开始</param>
/// <param name="key">搜索关键字</param>
/// <param name="indexId">被查找的指定次数的关键字</param>
/// <returns>如果存在则返回byte[]在流中指定索引次数出现的位置,否则返回 -1</returns>
public static long Search(this Stream stream, long beginPosition, byte[] key, int indexId)
{
if (stream == null || stream.Length <= beginPosition)
return -1;
if (key == null || stream.Length < key.Length)
return -1;
long i = -1;
long j = -1;
int times = 1;
int currentByte = int.MinValue;
for (i = beginPosition; i < stream.Length; i++)
{
if (stream.Length < key.Length + i)
break;
stream.Seek(i, SeekOrigin.Begin);
for (j = 0; j < key.Length; j++)
{
currentByte = stream.ReadByte();
if (currentByte != key[j])
break;
}
if (j == key.Length && times < indexId)
{
++times;
}
else if (j == key.Length && times == indexId)
{
return i;
}
if (currentByte == -1 || times > indexId)
break;
}
return -1;
}
}