1.首先,我们需要写一个选择发送文件的方法,这里使用了最常见OpenFileDialog方法,用于选取需要发送的文件.
string filePath = null; //文件的全路径 string fileName = null; //文件名称(不包含路径)
//选择要发送的文件
private void btnSelectFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofDialog = new OpenFileDialog();
if (ofDialog.ShowDialog(this) == DialogResult.OK)
{
fileName = ofDialog.SafeFileName; //获取选取文件的文件名
txtFileName.Text = fileName; //将文件名显示在文本框上
filePath = ofDialog.FileName; //获取包含文件名的全路径
}
}
2.选取文件之后,通过FileStream来读取文件字节数组,然后在读到的文件字节数组的索引为0的位置上增加了一个文件标识符1,目的是告知计算机该字节数组为文件字节数组.这里在向服务端发送文件的同时也发送了一个文件名(字符串信息),目的是在服务端成功接收文件后,自动将原文件名附加上去.
/// <summary>
/// 发送文件的方法
/// </summary>
/// <param name="fileFullPath">文件全路径(包含文件名称)</param>
private void SendFile(string fileFullPath)
{
if (fileFullPath == null)
{
MessageBox.Show("请选择需要发送的文件!");
return;
}
else if (fileFullPath != null)
{
//创建文件流
FileStream fs = new FileStream(fileFullPath, FileMode.Open);
//创建一个内存缓冲区 用于临时存储读取到的文件字节数组
byte[] arrClientFile = new byte[10 * 1024 * 1024];
//从文件流中读取文件的字节数组 并将其存入到缓冲区arrClientFile中
int realLength = fs.Read(arrClientFile, 0, arrClientFile.Length); //realLength 为文件的真实长度
byte[] arrClientSendedFile = new byte[realLength + 1];
//给新增标识符(实际要发送的)字节数组的索引为0的位置上增加一个标识符1
arrClientSendedFile[0] = 1; //告诉机器该发送的字节数组为文件
//将真实的文件字节数组完全拷贝到需要发送的文件字节数组中,从索引为1的位置开始存放,存放的字节长度为realLength.
//实际发送的文件字节数组 arrSendedFile包含了2部分 索引为0位置上的标识符1 以及 后面的真实文件字节数组
Buffer.BlockCopy(arrClientFile, 0, arrClientSendedFile, 1, realLength);
//调用发送信息的方法 将文件名发送出去
ClientSendMsg(fileName);
socketClient.Send(arrClientSendedFile);
txtMsg.AppendText("天之涯:" + GetCurrentTime() + "\r\n您发送了文件:" + fileName + "\r\n");
}
}
由于新增了一个类型标识符,这里便将之前服务端接收信息的方法稍微改了下. 当服务端接收到含有标识符为0的字节数组,则直接将字节数组转换成字符串,并附加到聊天信息文本框上.若接收到的字节数组含有标识符1(即文件),则调用保存文件的方法SaveFile()将其保存为原文件.
string strSRecMsg = null;
/// <summary>
/// 接收客户端发来的信息
/// </summary>
/// <param name="socketClientPara">客户端套接字的委托对象</param>
private void ServerRecMsg(object socketClientPara)
{
Socket socketServer = socketClientPara as Socket;
while (true)
{
//创建一个接收用的内存缓冲区 大小为10M字节数组
byte[] arrServerRecMsg = new byte[10 * 1024 * 1024];
//获取接收的数据,并存入内存缓冲区 返回一个字节数组的长度
int length = socketServer.Receive(arrServerRecMsg);
//判断发送过来的数据是文件还是普通文字信息
if (arrServerRecMsg[0] == 0) //0为文字信息
{
//将字节数组 转换为人可以读懂的字符串
strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 1, length - 1);//真实有用的文本信息要比接收到的少1(标识符)
//将接收到的信息附加到文本框txtMsg上
txtMsg.AppendText("天之涯:" + GetCurrentTime() + "\r\n" + strSRecMsg + "\r\n");
}
//如果发送过来的数据是文件
if (arrServerRecMsg[0] == 1)
{
SaveFile(arrServerRecMsg, length - 1);//同样实际文件长度需要-1(减去标识符)
}
}
}
SaveFile()方法里包含了FileStream的Write()方法,用于将接收到的文件字节数组保存为实际文件,这里Write()方法传入了3个参数,文件的字节数组,需要拷贝文件字节数组的初始位置以及拷贝的字节数组的长度.在获取到文件的同时,这里也获取了文件名(字符串信息),用于附加到另存为对话框的文件名上;同时截取了文件名的后缀,作为需要保存的文件类型.最后,在文件成功保存到服务端所在的计算机的同时,在聊天内容文本框中附加了成功接收的文件名和文件的保存路径.
/// <summary>
/// 保存接收文件的方法 包含一个字节数组参数 和 文件的长度
/// </summary>
/// <param name="arrFile">字节数组参数</param>
/// <param name="fileLength">文件的长度</param>
private void SaveFile(byte[] arrFile, int fileLength)
{
//创建一个用于保存文件的对话框
SaveFileDialog sfDialog = new SaveFileDialog();
//获取文件名的后缀 比如文本文件后缀 .txt
string fileNameSuffix = strSRecMsg.Substring(strSRecMsg.LastIndexOf("."));
sfDialog.Filter = "(*" + fileNameSuffix + ")|*" + fileNameSuffix + ""; //文件类型
sfDialog.FileName = strSRecMsg; //文件名
//如果点击了对话框中的保存文件按钮
if (sfDialog.ShowDialog(this) == DialogResult.OK)
{
string savePath = sfDialog.FileName; //获取文件的全路径
//保存文件
FileStream fs = new FileStream(savePath, FileMode.Create);
fs.Write(arrFile, 1, fileLength);
string fName = savePath.Substring(savePath.LastIndexOf("\\") + 1); //文件名 不带路径
string fPath = savePath.Substring(0, savePath.LastIndexOf("\\")); //文件路径 不带文件名
txtMsg.AppendText("SoFlash:" + GetCurrentTime() + "\r\n您成功接收了文件" + fName + "\r\n保存路径为:" + fPath + "\r\n");
}
}
string filePath = null; //文件的全路径 string fileName = null; //文件名称(不包含路径)
//选择要发送的文件
private void btnSelectFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofDialog = new OpenFileDialog();
if (ofDialog.ShowDialog(this) == DialogResult.OK)
{
fileName = ofDialog.SafeFileName; //获取选取文件的文件名
txtFileName.Text = fileName; //将文件名显示在文本框上
filePath = ofDialog.FileName; //获取包含文件名的全路径
}
}
2.选取文件之后,通过FileStream来读取文件字节数组,然后在读到的文件字节数组的索引为0的位置上增加了一个文件标识符1,目的是告知计算机该字节数组为文件字节数组.这里在向服务端发送文件的同时也发送了一个文件名(字符串信息),目的是在服务端成功接收文件后,自动将原文件名附加上去.
/// <summary>
/// 发送文件的方法
/// </summary>
/// <param name="fileFullPath">文件全路径(包含文件名称)</param>
private void SendFile(string fileFullPath)
{
if (fileFullPath == null)
{
MessageBox.Show("请选择需要发送的文件!");
return;
}
else if (fileFullPath != null)
{
//创建文件流
FileStream fs = new FileStream(fileFullPath, FileMode.Open);
//创建一个内存缓冲区 用于临时存储读取到的文件字节数组
byte[] arrClientFile = new byte[10 * 1024 * 1024];
//从文件流中读取文件的字节数组 并将其存入到缓冲区arrClientFile中
int realLength = fs.Read(arrClientFile, 0, arrClientFile.Length); //realLength 为文件的真实长度
byte[] arrClientSendedFile = new byte[realLength + 1];
//给新增标识符(实际要发送的)字节数组的索引为0的位置上增加一个标识符1
arrClientSendedFile[0] = 1; //告诉机器该发送的字节数组为文件
//将真实的文件字节数组完全拷贝到需要发送的文件字节数组中,从索引为1的位置开始存放,存放的字节长度为realLength.
//实际发送的文件字节数组 arrSendedFile包含了2部分 索引为0位置上的标识符1 以及 后面的真实文件字节数组
Buffer.BlockCopy(arrClientFile, 0, arrClientSendedFile, 1, realLength);
//调用发送信息的方法 将文件名发送出去
ClientSendMsg(fileName);
socketClient.Send(arrClientSendedFile);
txtMsg.AppendText("天之涯:" + GetCurrentTime() + "\r\n您发送了文件:" + fileName + "\r\n");
}
}
由于新增了一个类型标识符,这里便将之前服务端接收信息的方法稍微改了下. 当服务端接收到含有标识符为0的字节数组,则直接将字节数组转换成字符串,并附加到聊天信息文本框上.若接收到的字节数组含有标识符1(即文件),则调用保存文件的方法SaveFile()将其保存为原文件.
string strSRecMsg = null;
/// <summary>
/// 接收客户端发来的信息
/// </summary>
/// <param name="socketClientPara">客户端套接字的委托对象</param>
private void ServerRecMsg(object socketClientPara)
{
Socket socketServer = socketClientPara as Socket;
while (true)
{
//创建一个接收用的内存缓冲区 大小为10M字节数组
byte[] arrServerRecMsg = new byte[10 * 1024 * 1024];
//获取接收的数据,并存入内存缓冲区 返回一个字节数组的长度
int length = socketServer.Receive(arrServerRecMsg);
//判断发送过来的数据是文件还是普通文字信息
if (arrServerRecMsg[0] == 0) //0为文字信息
{
//将字节数组 转换为人可以读懂的字符串
strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 1, length - 1);//真实有用的文本信息要比接收到的少1(标识符)
//将接收到的信息附加到文本框txtMsg上
txtMsg.AppendText("天之涯:" + GetCurrentTime() + "\r\n" + strSRecMsg + "\r\n");
}
//如果发送过来的数据是文件
if (arrServerRecMsg[0] == 1)
{
SaveFile(arrServerRecMsg, length - 1);//同样实际文件长度需要-1(减去标识符)
}
}
}
SaveFile()方法里包含了FileStream的Write()方法,用于将接收到的文件字节数组保存为实际文件,这里Write()方法传入了3个参数,文件的字节数组,需要拷贝文件字节数组的初始位置以及拷贝的字节数组的长度.在获取到文件的同时,这里也获取了文件名(字符串信息),用于附加到另存为对话框的文件名上;同时截取了文件名的后缀,作为需要保存的文件类型.最后,在文件成功保存到服务端所在的计算机的同时,在聊天内容文本框中附加了成功接收的文件名和文件的保存路径.
/// <summary>
/// 保存接收文件的方法 包含一个字节数组参数 和 文件的长度
/// </summary>
/// <param name="arrFile">字节数组参数</param>
/// <param name="fileLength">文件的长度</param>
private void SaveFile(byte[] arrFile, int fileLength)
{
//创建一个用于保存文件的对话框
SaveFileDialog sfDialog = new SaveFileDialog();
//获取文件名的后缀 比如文本文件后缀 .txt
string fileNameSuffix = strSRecMsg.Substring(strSRecMsg.LastIndexOf("."));
sfDialog.Filter = "(*" + fileNameSuffix + ")|*" + fileNameSuffix + ""; //文件类型
sfDialog.FileName = strSRecMsg; //文件名
//如果点击了对话框中的保存文件按钮
if (sfDialog.ShowDialog(this) == DialogResult.OK)
{
string savePath = sfDialog.FileName; //获取文件的全路径
//保存文件
FileStream fs = new FileStream(savePath, FileMode.Create);
fs.Write(arrFile, 1, fileLength);
string fName = savePath.Substring(savePath.LastIndexOf("\\") + 1); //文件名 不带路径
string fPath = savePath.Substring(0, savePath.LastIndexOf("\\")); //文件路径 不带文件名
txtMsg.AppendText("SoFlash:" + GetCurrentTime() + "\r\n您成功接收了文件" + fName + "\r\n保存路径为:" + fPath + "\r\n");
}
}