繁体   English   中英

如何使用C#同时读取/写入文本文件?

[英]How can I simultaneously read/write form a text file using C#?

我创建了多个服务器,每个服务器都必须向自己的客户端发送一些数据。 我正在使用TCP / IP协议。 为了防止由于客户端断开连接而造成的任何数据丢失,我将文本文件用作缓冲区。 因此,在程序中,每个服务器都有一个线程,用于不断检查客户端是否已连接。 如果已连接,则它将从缓冲区读取并将其发送给客户端。 每当必须将一些新数据发送到客户端时,我首先要检查客户端是否已连接。如果客户端未连接,则将数据写入同一缓冲区文本文件中。 我面临的问题是,当线程正在从文件中读取文件时,我无法写入该文件。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsFormsApplication1
{

    public class TcpIp
    {
        public int machinePort;
        public static int port1 = 1024;
        public static int count = 0;
        public string bufferName;
        FileStream buffer;
        Socket client;
        public IPAddress localIp;
        public TcpListener sender;
        StreamReader reader ;
        FileStream iStream;

        //this.get
        public TcpIp(string id)
        {
            this.machinePort = port1 + count;
            while (!isAvailable(this.machinePort))
            {
                count++;
                this.machinePort = port1 + count;
            }
            this.bufferName = WindowsFormsApplication1.Program.path + "machine_" + id + ".txt";

            buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
            localIp = IPAddress.Parse(WindowsFormsApplication1.Program.ip);
            sender = new TcpListener(localIp, this.machinePort);

          // this.oStream = new FileStream(this.bufferName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
           //this.iStream = new FileStream(this.bufferName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
          // reader = new StreamReader(this.iStream);
        }

        bool isAvailable(int port)
        {
            bool isAvailable = true;
            IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
            TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

            foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
            {
                if (tcpi.LocalEndPoint.Port == port)
                {
                    isAvailable = false;
                    break;
                }
            }
            return isAvailable;
        }

        public void createServer()
        {
                this.sender.Start();
                string line;
                reader = new StreamReader(buffer);
                //client = sender.AcceptSocket();
                while (true)
                {

                    line = reader.ReadLine();
                    if (!connected())
                    {
                        client = sender.AcceptSocket();
                    }

                    while (reader.EndOfStream && line != null)
                    {
                        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(line);
                        client.Send(bytes, 0, bytes.Length, SocketFlags.None);
                        line = reader.ReadLine();
                    }
                   // iStream.Flush();    
                    Thread.Sleep(3000);
                    //reader = new StreamReader(iStream);
                }
        }

        public void writeToClient(string data)
        {
            if (connected())
            {
                //send data to client
                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
                //System.Buffer.BlockCopy(data.ToCharArray(), 0, bytes, 0, bytes.Length);
                this.client.Send(bytes, 0, bytes.Length, SocketFlags.None);
            }
            else
            {
                //write to file
                while (true)
                {
                    try
                    {
                        StreamWriter sw = File.AppendText(this.bufferName);
                        sw.WriteLine(data);
                        sw.Close();
                        break;           
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("WaitForFile {0} failed to get an exclusive lock: "+ex.Message );
                        // Wait for the lock to be released
                        System.Threading.Thread.Sleep(500);
                    }

                }
            }
        }

        bool connected()
        {
            if (client == null)
                return false;
            else 
                return client.Connected;
        }
    }
}

任何启发将不胜感激。 谢谢 :)

实际的问题是您混淆了对该文件的访问。

您通过buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);打开流buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); 为了从打开的流中创建一个StreamReader ,供以后由reader = new StreamReader(buffer);

OTOH,您想通过StreamWriter获得一个StreamWriter来写入文件StreamWriter sw = File.AppendText(this.bufferName); 这会尝试再次打开文件,由于文件共享模式不匹配而失败。

因此,您需要通过相同的“句柄”(在此为FileStream)访问用于写入和读取的文件。 此外,不要忘记通过某种锁定机制对访问进行序列化以使其成为线程安全的。 否则,您将获得损坏的数据。 您可能需要维护读/写指针(Stream.Position)。

您不能同时从同一文本文件读取和写入。

如果您确实要使用文本文件,为什么不使用它们中的两个:一个要读取,一个要写入。 一旦读取文件为空->读取文件即为您的新写入文件,反之亦然。

这听起来很合理,因为两个文件正在使用中,所以两个线程不可能同时访问一个文件。

想象一下,甚至有可能,您会有一些非常奇怪的行为。

为什么不使用lock()来确保在给定时间只有一个线程可以访问文件?

借助异步编程,您无需等到释放锁就可以继续执行程序。

您将必须创建这样的线程

Thread thread = new Thread(yourMethod());

当您有多个线程时,您需要的是ReaderWriterLockSlim。 这是链接

它使您可以通过多个线程读取文件,但可以使用一个线程写入文件。 我认为这可以解决您的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM