简体   繁体   English

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

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

I have multiple servers created.Each one has to send some data to its own client. 我创建了多个服务器,每个服务器都必须向自己的客户端发送一些数据。 I am using TCP/IP protocol. 我正在使用TCP / IP协议。 To prevent any data loss due to client getting disconnected, I am using a text file as a buffer. 为了防止由于客户端断开连接而造成的任何数据丢失,我将文本文件用作缓冲区。 So in the program , there is a thread for each server which keeps on checking if the client is connected or not. 因此,在程序中,每个服务器都有一个线程,用于不断检查客户端是否已连接。 If it is connected then it reads from the buffer and sends it to client. 如果已连接,则它将从缓冲区读取并将其发送给客户端。 whenever some new data has to be send to client , I am first checking if client is connected.If client isn't connected then I am writing data to the same buffer text file. 每当必须将一些新数据发送到客户端时,我首先要检查客户端是否已连接。如果客户端未连接,则将数据写入同一缓冲区文本文件中。 The problem I am facing is that I am unable to write to the file while thread is reading from it. 我面临的问题是,当线程正在从文件中读取文件时,我无法写入该文件。

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;
        }
    }
}

Any enlightenment would be appreciated. 任何启发将不胜感激。 Thank you :) 谢谢 :)

The actual problem is that you mix up access to the file. 实际的问题是您混淆了对该文件的访问。

You open a stream by buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); 您通过buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);打开流buffer = new FileStream(this.bufferName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); in order to create a StreamReader from the opened stream for later reading by reader = new StreamReader(buffer); 为了从打开的流中创建一个StreamReader ,供以后由reader = new StreamReader(buffer); .

OTOH, you want get a StreamWriter for writing to the file by StreamWriter sw = File.AppendText(this.bufferName); OTOH,您想通过StreamWriter获得一个StreamWriter来写入文件StreamWriter sw = File.AppendText(this.bufferName); . This tries to open the file again which fails because of mismatching file sharing mode. 这会尝试再次打开文件,由于文件共享模式不匹配而失败。

So you need to access the file for writing and reading via the very same "handle" (here FileStream). 因此,您需要通过相同的“句柄”(在此为FileStream)访问用于写入和读取的文件。 Furthermore, don't forget to serialize access by some locking mechanism in order to make it thread-safe. 此外,不要忘记通过某种锁定机制对访问进行序列化以使其成为线程安全的。 Otherwise, you'll get corrupted data. 否则,您将获得损坏的数据。 You'll probably need to maintain the read/write pointer (Stream.Position). 您可能需要维护读/写指针(Stream.Position)。

You can't read and write from the same text file at the same time. 您不能同时从同一文本文件读取和写入。

If you really want to use text files, why not using 2 of them: One to read from and one to write into. 如果您确实要使用文本文件,为什么不使用它们中的两个:一个要读取,一个要写入。 Once the read file is empty -> the read file is your new write file and vice versa. 一旦读取文件为空->读取文件即为您的新写入文件,反之亦然。

That sounds logic, it's not possible for 2 threads to access a file as the same time, because the file is in use. 这听起来很合理,因为两个文件正在使用中,所以两个线程不可能同时访问一个文件。

Imagine that it's even possible, you will have some very strange behaviour. 想象一下,甚至有可能,您会有一些非常奇怪的行为。

Why are you not using a lock() to make sure that only a single thread can access the file at a given time? 为什么不使用lock()来确保在给定时间只有一个线程可以访问文件?

And with async programming, you don't need to wait until the lock is released before continueing your program. 借助异步编程,您无需等到释放锁就可以继续执行程序。

You will have to create Threads like this 您将必须创建这样的线程

Thread thread = new Thread(yourMethod());

When you have multiple threads then what you need is ReaderWriterLockSlim. 当您有多个线程时,您需要的是ReaderWriterLockSlim。 Here is the link . 这是链接

It lets you to read a file by multiple threads but write the file with one Thread. 它使您可以通过多个线程读取文件,但可以使用一个线程写入文件。 I think this will solve your problem. 我认为这可以解决您的问题。

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

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