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

时间:2014-05-26 12:02:56

标签: c# multithreading file

我创建了多个服务器。每个服务器都必须将一些数据发送到自己的客户端。我正在使用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;
        }
    }
}

任何启蒙都会受到赞赏。谢谢:))

4 个答案:

答案 0 :(得分:2)

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

您可以buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);打开一个流,以便从打开的流中创建StreamReader,以便reader = new StreamReader(buffer);稍后阅读。

OTOH,您希望获得StreamWriter StreamWriter sw = File.AppendText(this.bufferName);来写文件{{1}}。这会尝试再次打开文件,因为文件共享模式不匹配而失败。

所以你需要通过相同的"句柄来访问文件进行写作和阅读。 (这里是FileStream)。此外,不要忘记通过某种锁定机制序列化访问,以使其成为线程安全的。否则,您将收到损坏的数据。您可能需要维护读/写指针(Stream.Position)。

答案 1 :(得分:1)

您无法同时从同一文本文件中读取和写入。

如果您真的想使用文本文件,为什么不使用其中的两个: 一个读取,一个读写。 一旦读取文件为空 - >读取文件是您的新写入文件,反之亦然。

答案 2 :(得分:0)

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

想象一下,即使有可能,你也会有一些非常奇怪的行为。

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

使用异步编程,您无需等到锁定被释放后再继续执行程序。

答案 3 :(得分:0)

你必须像这样创建线程

Thread thread = new Thread(yourMethod());

当你有多个线程时,你需要的是ReaderWriterLockSlim。这是link

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