C# 如何通过网络复制频繁使用的文件?

C# 如何通过网络复制频繁使用的文件?,c#,.net,network-programming,C#,.net,Network Programming,我需要通过网络复制一个大文件(大约20MB)。通常情况下,这不会是一个问题,但是,与文件位于同一个框中的应用程序相当频繁地(大约每秒一次)写入文件 因此,由于文件经常写入,file.Copy调用经常失败。我还尝试了File.ReadAllLines,它似乎每次都能正常工作,但需要花费很长时间 有没有更好、更高效、更安全的方法通过网络复制文件 另外,该文件是由一个利用Log4Net的进程写入的。而且,如果有人想知道,写文件的过程不在我的掌握之中。您可以在打开文件时使用fileshare字段,以便在

我需要通过网络复制一个大文件(大约20MB)。通常情况下,这不会是一个问题,但是,与文件位于同一个框中的应用程序相当频繁地(大约每秒一次)写入文件

因此,由于文件经常写入,
file.Copy
调用经常失败。我还尝试了
File.ReadAllLines
,它似乎每次都能正常工作,但需要花费很长时间

有没有更好、更高效、更安全的方法通过网络复制文件


另外,该文件是由一个利用Log4Net的进程写入的。而且,如果有人想知道,写文件的过程不在我的掌握之中。

您可以在打开文件时使用fileshare字段,以便在访问文件时允许其他进程访问该文件,不幸的是,如果您的进程不是锁定文件的进程,那么您无法释放它,并且您已经提到,您无法更改正在编写的代码,通过在fileshare字段中允许r/w,您可以允许其他进程在复制文件时访问该文件。您可以编写一个小函数来检查文件是否被锁定,并更改代码,以便在文件被锁定时,您可以一直进行检查,直到它解锁,然后复制它。

很可能是该文件。复制无法获得文件的独占锁

考虑到
File.Move
是一种快速操作,即使是在网络上。如果文件不需要在上一个应用程序中保留,则可以运行

for (int i = 0; i < 10; i++)
{
    try {
        File.Move(logFilePath, tempPathOnRemoteServer);
    } catch (Exception) { 
        if (i == 9)
            throw new Exception("Could not acquire lock");
        System.Threading.Thread.Sleep(1000 * (i+1)); }
}
File.Copy(tempPathOnRemoteServer, endPathOnLocalHost);
for(int i=0;i<10;i++)
{
试一试{
Move(logFilePath,tempaphnremoteserver);
}捕获(例外){
如果(i==9)
抛出新异常(“无法获取锁”);
System.Threading.Thread.Sleep(1000*(i+1));}
}
Copy(tempPathnRemoteServer,endPathnLocalHost);
如果日志应用程序可以在文件打开时从移动的文件中恢复,则不会出现问题


或者,如果无法移动文件,请使用与上面相同的代码,将file.Move替换为file.Copy,但是,如果复制时间过长,您的独占锁可能会导致其他应用程序出现问题。

使用FileStream类读取文件,不要忘记在重载构造函数中为FileAccess和FileShare设置适当的值

FileStream(String, FileMode, FileAccess, FileShare)

首先在本地制作一个副本怎么样?这将非常快,并且会保留副本的状态,然后上载副本,最后删除副本?

如果您无法修改写入文件的程序,那么您的选项就有点有限。我想到的两种可能性是:

以独占方式打开文件,并在循环中复制:

using (var fin = File.Open(InputFilename, FileMode.Open, FileAccess.Read, FileShare.None))
{
    using (var fout = File.OpenWrite(OutputFilename))`
    {
        int bytesRead = 0;
        var buffer = new byte[65536];
        while ((bytesRead = fin.Read(buffer, 0, buffer.Length)) > 0)
        {
            fout.Write(buffer, 0, bytesRead);
        }
    }
}
当您试图打开Log4Net文件进行读取时,如果Log4Net打开该文件进行写入,则必须编写代码来处理引发的异常。该代码应该稍等片刻,然后重试

这里潜在的缺点是,如果Log4Net无法写入文件(因为它是为独占访问而打开的),它可能会抛出异常。如果Log4Net不希望您以独占方式打开文件,那么

只需重命名文件,然后随意复制即可。如果在尝试重命名时Log4Net打开了该文件,那么代码将抛出异常。你可以再试一次。如果Log4Net在重命名文件后试图写入该文件,Log4Net将使用该名称创建一个新文件

我看不到任何其他选择


顺便说一下,20MB并不是一个大文件。在现代网络速度下,您应该能够在不到一秒钟的时间内复制它。

您可以尝试这样处理它:

string pathToFile = "path-to-your-file" ;
using ( Stream     s = File.Open( pathToFile , FileMode.Open , FileAccess.Read , FileShare.ReadWrite ) )
using ( TextReader r = new StreamReader( s ) )
{
    string fileContents = r.ReadToEnd() ;
    process( fileContents ) ;
}
如果写入文件的进程不愿意将其共享以供读取,那么您就是SOL

然而 . . . 你说:

另外,该文件是由一个利用Log4Net的进程写入的。 而且,如果有人想知道的话,写作的过程是我无法掌控的

您试图访问的文件是由Appender生成的,如或

如果是这样的话,默认的日志记录模型是
FileAppender.ExclusiveLock
,它使用独占锁将文件保持在打开状态,但IIRC仍然愿意共享以供读取

但是获得所需结果(通过网络发送文件)的一种更简单的方法(为什么要重新发明轮子?)是使用。您可以向源应用程序Log4Net配置文件添加一个appender,这将对您有所帮助。您可以使用:

  • “用于将事件传递到远程接收器。这是实现RemotingAppender.IRemoteLoggingSink接口的任何对象。它使用.NET远程处理传递事件。要将事件传递到的对象通过设置Appender接收器属性指定。”

  • “接受套接字连接并将日志消息流回到客户端。输出以telnet友好的方式提供,以便可以通过TCP/IP套接字监控日志。这允许对应用程序日志进行简单的远程监控。 默认端口为23(telnet端口)。”

无论哪种方式,您都只需要编写一个简单的服务来处理入站日志消息

就效率而言,如果是log4net输出,您只需要跟踪最高点并复制新内容

  • 打开源文件进行读取
  • 创建目标文件
  • 通过网络复制数据直到文件结束
  • 保存流中的当前位置
  • 睡眠
  • 打开源文件进行读取
  • 打开要追加的目标文件
  • 查找到流中记住的位置(可能不再位于文件末尾)
  • 通过网络复制数据,直到文件结束,并附加到目标文件
  • 重复一遍,从4号开始

  • 只是想一想。

    好的,那么,另一个选择就是总是模拟地写入两个文件。一吨