如何在复制数据之前在服务器端获取客户端文件名
How to get client file name on server side before copying data
我在我的文件共享应用程序中用尽了想法,我正在使用 FileStream.copyto()
从客户端接收服务器上的数据。它运行良好,但目前我已将缓冲区大小设置为 1024
对于 var bytesread = fs.Read(buffer, 0, buffer.Length)
但我有两个问题:
我不确定它在缓冲区之前允许的最大大小 overflow.Should 它是一种命中和试用方法吗?或者在 WLAN 上传输数据是否有固定的字节数限制。
当我使用带有扩展名的硬编码文件名检查服务器端的代码时,就像我在 FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)
中预定义的 path
一样,它可以工作,但我将如何启用它来获取文件名。我的意思是,我应该使用修复协议,我应该为它分配一个预数据字节,然后在数据复制之前在服务器端检查和接收吗?
有什么好主意。
没有代码和更精确的描述,很难知道您在这里实际需要什么。但是,如果我理解正确的话,您有一个场景,其中客户端端点正在读取本地文件并将数据发送到服务器端点,并且服务器端点正在为 I/O 使用 NetworkStream
对象。
假设是这种情况,那么客户端可以包含这样的文件名:
void TransmitFileName(Stream stream, string fileName)
{
byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileName),
fileNameLengthBytes = BitConverter.GetBytes(fileNameBytes.Length);
stream.Write(fileNameLengthBytes, 0, 4);
stream.Write(fileNameBytes, 0, fileNameBytes.Length);
}
在服务器上,假设您已经将数据读入适当大小的 byte[]
缓冲区,您可以按如下方式解码信息:
string DecodeFileName(Stream stream)
{
byte[] fileNameLengthBuffer = new byte[4];
FillBufferFromStream(stream, fileNameLengthBuffer);
int fileNameLength = BitConverter.ToInt32(fileNameLengthBuffer, 0);
byte[] fileNameBuffer = new byte[fileNameLength];
FillBufferFromStream(stream, fileNameBuffer);
return Encoding.UTF8.GetString(fileNameBuffer);
}
void FillBufferFromStream(Stream stream, byte[] buffer)
{
int cbTotal = 0;
while (cbTotal < buffer.Length)
{
int cbRead = stream.Read(buffer, cbTotal, buffer.Length - cbTotal);
if (cbRead == 0)
{
throw new InvalidDataException("premature end-of-stream");
}
cbTotal += cbRead;
}
}
我将实际的服务器端 I/O 留作 reader 的练习。但是请注意,使用 TCP 时,您不能保证任何给定的读取操作都会阻塞,直到您请求的所有字节都被读取为止。因此,您需要连续读取,直到获得成功解码操作所需的所有字节。
我已经添加了必要的逻辑来从 NetworkStream
对象中读取数据。请注意,我包含一个辅助方法,它将检查实际读取的字节数,并继续读取字节,填充缓冲区,直到实际读取所需的字节数。在您实际读取了您希望的所有字节之前,您不能指望 Read()
方法进行阻塞。
实际上,这可能意味着分两部分进行解码:第一部分获取 fileNameLength
值(你知道这需要 4 个字节),第二部分获取文件名(长度只有在解码 fileNameLength
值后你才会知道其中的内容)。
在文件名字节之后,您可以像以前一样传输文件数据本身。
编辑: 要在您发布的代码的上下文中使用以上内容……
Client: 在发送实际文件数据之前调用 TransmitFileName()
方法。例如:
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
TransmitFileName(netstream, Path.GetFileName(path));
...
Server: 在收到实际文件数据之前调用 DecodeFileName()
方法。例如:
//open a stream to get data
NetworkStream netStream = client.GetStream();
//Directory to save
string DirName = @"D:\NewFolder\Test\";
//File Name is requirement here to save data at.
string fileloc = Path.Combine(DirName, DecodeFileName(netStream));
MessageBox.Show(fileloc);
我在我的文件共享应用程序中用尽了想法,我正在使用 FileStream.copyto()
从客户端接收服务器上的数据。它运行良好,但目前我已将缓冲区大小设置为 1024
对于 var bytesread = fs.Read(buffer, 0, buffer.Length)
但我有两个问题:
我不确定它在缓冲区之前允许的最大大小 overflow.Should 它是一种命中和试用方法吗?或者在 WLAN 上传输数据是否有固定的字节数限制。
当我使用带有扩展名的硬编码文件名检查服务器端的代码时,就像我在
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)
中预定义的path
一样,它可以工作,但我将如何启用它来获取文件名。我的意思是,我应该使用修复协议,我应该为它分配一个预数据字节,然后在数据复制之前在服务器端检查和接收吗?
有什么好主意。
没有代码和更精确的描述,很难知道您在这里实际需要什么。但是,如果我理解正确的话,您有一个场景,其中客户端端点正在读取本地文件并将数据发送到服务器端点,并且服务器端点正在为 I/O 使用 NetworkStream
对象。
假设是这种情况,那么客户端可以包含这样的文件名:
void TransmitFileName(Stream stream, string fileName)
{
byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileName),
fileNameLengthBytes = BitConverter.GetBytes(fileNameBytes.Length);
stream.Write(fileNameLengthBytes, 0, 4);
stream.Write(fileNameBytes, 0, fileNameBytes.Length);
}
在服务器上,假设您已经将数据读入适当大小的 byte[]
缓冲区,您可以按如下方式解码信息:
string DecodeFileName(Stream stream)
{
byte[] fileNameLengthBuffer = new byte[4];
FillBufferFromStream(stream, fileNameLengthBuffer);
int fileNameLength = BitConverter.ToInt32(fileNameLengthBuffer, 0);
byte[] fileNameBuffer = new byte[fileNameLength];
FillBufferFromStream(stream, fileNameBuffer);
return Encoding.UTF8.GetString(fileNameBuffer);
}
void FillBufferFromStream(Stream stream, byte[] buffer)
{
int cbTotal = 0;
while (cbTotal < buffer.Length)
{
int cbRead = stream.Read(buffer, cbTotal, buffer.Length - cbTotal);
if (cbRead == 0)
{
throw new InvalidDataException("premature end-of-stream");
}
cbTotal += cbRead;
}
}
我将实际的服务器端 I/O 留作 reader 的练习。但是请注意,使用 TCP 时,您不能保证任何给定的读取操作都会阻塞,直到您请求的所有字节都被读取为止。因此,您需要连续读取,直到获得成功解码操作所需的所有字节。
NetworkStream
对象中读取数据。请注意,我包含一个辅助方法,它将检查实际读取的字节数,并继续读取字节,填充缓冲区,直到实际读取所需的字节数。在您实际读取了您希望的所有字节之前,您不能指望 Read()
方法进行阻塞。
实际上,这可能意味着分两部分进行解码:第一部分获取 fileNameLength
值(你知道这需要 4 个字节),第二部分获取文件名(长度只有在解码 fileNameLength
值后你才会知道其中的内容)。
在文件名字节之后,您可以像以前一样传输文件数据本身。
编辑: 要在您发布的代码的上下文中使用以上内容……
Client: 在发送实际文件数据之前调用 TransmitFileName()
方法。例如:
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
TransmitFileName(netstream, Path.GetFileName(path));
...
Server: 在收到实际文件数据之前调用 DecodeFileName()
方法。例如:
//open a stream to get data
NetworkStream netStream = client.GetStream();
//Directory to save
string DirName = @"D:\NewFolder\Test\";
//File Name is requirement here to save data at.
string fileloc = Path.Combine(DirName, DecodeFileName(netStream));
MessageBox.Show(fileloc);