【.NET流操作】FileStream、NetWorkStream

FileStream

FileStream流继承于Stream类,代表一个文件流,使用FileStream类可以对文件进行读取、写入、打开和关闭操作
常用构造函数:

public FileStream(string path, FileMode mode, FileAccess access);

参数说明:
path指明文件所在的路径信息;
mode是FileMode的枚举值,表示文件打开或创建的方式,含义如下:

  • CreateNew:指定操作系统应创建新文件,如果文件已经存在,则引发IOException;
  • Create:指定操作系统应创建新文件,如果文件已经存在,它将被覆盖;
  • Open:指定操作系统应打开现有文件,如果文件不存在,则引发FileNotFoundException;
  • OpenOrCreate:指定操作系统应打开文件,如果文件不存在,则创建新文件;
  • Truncate:指定操作系统应打开现有文件,文件一旦打开,就将截断为零字节大小;
  • Append:打开先有文件并把Position设置至文件尾,如果文件不存在将创建新文件。Append只能同FileAccess.Write一起使用;

access是FileAccess的枚举值,它控制对文件的访问权限,含义如下:

  • Read:打开文件用于只读;
  • Write:打开文件用于只写;
  • ReadWrite:打开文件,用于读写;

NetWorkStream(网络流)

网络流的意思是数据在网络的各个位置之间是以连续的字节形式传输的,NetWorkStream只能用于面向连接的套接字。

  • NetworkStream只能用在具有Tcp/IP协议之中,如果用在UDP中编译不报错,会报异常
  • 我们可以通过NetworkStream简化Socket开发
  • 用法和普通流方法几乎一模一样,但具有特殊性。NetworkStream基于安全上的考虑不支持 Posion属性或Seek方法,寻找或改变流的位置,如果试图强行使用会报出NotSupport的异常

构造

NetworkStream (Socket) 为指定的 Socket 创建 NetworkStream 类的新实例
NetworkStream (Socket, Boolean ownsSocket) 用指定的 Socket 所属权为指定的 Socket,ownsSocket表示指示NetworkStream是否拥有该Socket
NetworkStream (Socket, FileAccess) 用指定的访问权限为指定的 Socket 创建FileAccess 值的按位组合,这些值指定授予所提供的 Socket 上的 NetworkStream 的访问类型
NetworkStream (Socket, FileAccess, Boolean ownsSocket)

属性

  • CanSeek :用于指示流是否支持查找,它的值始终为 false
  • DataAvailable 指示在要读取的 NetworkStream 上是否有可用的数据。一般来说通过判断这个属性来判断NetworkStream中是否有数据
  • Length:NetworkStream不支持使用Length属性,强行使用会发生NotSupportedException异常
  • Position: NetworkStream不支持使用Position属性,强行使用会发生NotSupportedException异常

方法

同样,NetworkStream的方法大致重写或继承了Stream的方法
但是以下方法必须注意:

  • int Read(byte[] buffer,int offset,int size)
    该方法将数据读入 buffer 参数并返回成功读取的字节数。如果没有可以读取的数据,则 Read 方法返回 0。Read 操作将读取尽可能多的可用数据,
    直至达到由 size 参数指定的字节数为止。如果远程主机关闭了连接并且已接收到所有可用数据,Read 方法将立即完成并返回零字节。
  • long Seek(long offset, SeekOrigin origin)
    将流的当前位置设置为给定值。此方法当前不受支持,总是引发 NotSupportedException
  • void Write(byte[] buffer, int offset,int size)
    Write方法在指定的 offset 处启动,并将 buffer 内容中的 size 字节发送到网络。Write 方法将一直处于阻止状态(可以用异步解决),直到发送了请求
    的字节数或引发 SocketException 为止。如果收到 SocketException,可以使用 SocketException.ErrorCode 属性获取特定的错误代码。

案例

创建一个客户端向服务端传输图片的小示例
服务端:监听客户端传来的图片信息

/// <summary>
   /// 服务端监听客户端信息,一旦有发送过来的信息,便立即处理
   /// </summary>
    class Program
    {
        //全局TcpClient
       static TcpClient client;
        //文件流建立到磁盘上的读写流
       static FileStream fs = new FileStream("E:\\abc.jpg", FileMode.Create);
        //buffer
       static int bufferlength = 200;
       static byte[] buffer = new byte[bufferlength];
        //网络流
       static NetworkStream ns;

        static void Main(string[] args)
        {
            ConnectAndListen();
        }

       static void ConnectAndListen() 
        {
           //服务端监听任何IP 但是端口号是80的连接
            TcpListener listener = new TcpListener(IPAddress.Any,80);
           //监听对象开始监听
            listener.Start();
            while(true)
            {
                Console.WriteLine("等待连接");
                //线程会挂在这里,直到客户端发来连接请求
                client = listener.AcceptTcpClient();
                Console.WriteLine("已经连接");
                //得到从客户端传来的网络流
                ns = client.GetStream();
                //如果网络流中有数据
                    if (ns.DataAvailable)
                    {
                        //同步读取网络流中的byte信息
                       // do
                      //  {
                      //  ns.Read(buffer, 0, bufferlength);
                      //} while (readLength > 0);

                        //异步读取网络流中的byte信息
                        ns.BeginRead(buffer, 0, bufferlength, ReadAsyncCallBack, null);
                    }
            }
        }

       /// <summary>
       /// 异步读取
       /// </summary>
       /// <param name="result"></param>
       static void ReadAsyncCallBack(IAsyncResult result) 
       {
           int readCount;
           //获得每次异步读取数量
           readCount = client.GetStream().EndRead(result);
           //如果全部读完退出,垃圾回收
           if (readCount < 1) 
           {
               client.Close();
               ns.Dispose();
               fs.Dispose();
               return; 
           }
          //将网络流中的图片数据片段顺序写入本地
           fs.Write(buffer, 0, 200);
           //再次异步读取
           ns.BeginRead(buffer, 0, 200, ReadAsyncCallBack, null);
       }
    }

客户端:先连接上服务端后在发送图片,注意如果是双向通信的话最好将客户端和服务端的项目设置为多个启动项便于调试

class Program
    {
       /// <summary>
       /// 客户端
       /// </summary>
       /// <param name="args"></param>
        static void Main(string[] args)
        {
            SendImageToServer("xxx.jpg");
        }   

        static void SendImageToServer(string imgURl)
        {
            if (!File.Exists(imgURl)) return;
             //创建一个文件流打开图片
            FileStream fs = File.Open(imgURl, FileMode.Open);
            //声明一个byte数组接受图片byte信息
            byte[] fileBytes = new byte[fs.Length];
            using (fs)
            {
                //将图片byte信息读入byte数组中
                fs.Read(fileBytes, 0, fileBytes.Length);
                fs.Close();
            }
            //找到服务器的IP地址
            IPAddress address = IPAddress.Parse("127.0.0.1");
            //创建TcpClient对象实现与服务器的连接
            TcpClient client = new TcpClient();
            //连接服务器
            client.Connect(address, 80);
            using (client)
            {
                //连接完服务器后便在客户端和服务端之间产生一个流的通道
                NetworkStream ns = client.GetStream();
                using (ns)
                {
                    //通过此通道将图片数据写入网络流,传向服务器端接收
                   ns.Write(fileBytes, 0, fileBytes.Length);
                }
            }
        }
    }
posted @ 2022-06-05 20:27  .Neterr  阅读(515)  评论(0编辑  收藏  举报