簡體   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