如何打开一个文件进行写入以安全地允许其他程序读取?

Posted

技术标签:

【中文标题】如何打开一个文件进行写入以安全地允许其他程序读取?【英文标题】:How can I open a file for writing that safely allows other programs to read? 【发布时间】:2016-05-07 04:13:24 【问题描述】:

我正在打开一个 FileStream 并使用以下两个代码 sn-ps 向其写入行:

public static System.IO.FileStream OpenFileStream(string FullFilename) 
    return new System.IO.FileStream(FullFilename, System.IO.FileMode.OpenOrCreate,
        System.IO.FileAccess.ReadWrite, System.IO.FileShare.Read);


public static void WriteLine(System.IO.FileStream fileStream, string str) 
    fileStream.Seek(0, System.IO.SeekOrigin.End);
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str + "\r\n");
    fileStream.Write(bytes, 0, bytes.Length);
    fileStream.Flush();

被访问的文件,即OpenFileStream中的FullFilename参数,是一个CSV文件。打开文件后,要求能够看到到目前为止写入 CSV 文件的内容。

我一直在使用 Microsoft Excel,当 Excel 打开文件时,它会注意到该文件正在使用中并给我一个对话框,告诉我我只能获得只读访问权限。尽管如此,即使OpenFileStream 授予其他程序的访问权限是System.IO.FileShare.Read,Excel 尝试打开文件的行为有时也会导致在获得打开的 FileStream 的程序中引发异常。

被抛出的异常是带有消息The process cannot access the file because another process has locked a portion of the fileSystem.IO.IOException,它可以在访问FileStreamWriteLine 函数中的任何位置被抛出。

如何防止其他程序(如 Excel)尝试读取文件时引发任何异常?

【问题讨论】:

您不能将文件流的内容复制到内存流中,以便不再访问该文件还是我误解了这个问题? @AlexanderDerck 我需要能够看到到目前为止所写的内容,所以我认为存储在内存中没有帮助。 看来这是正确的方法。问题是当文件已经打开以供写入时 - 然后您无法打开它。 @i486 我不想打开 Excel 中的文字,只是阅读。但是,为“只读”打开的行为仍然会导致抛出异常。 @Stochasticly Excel 导致LockFileEx (Win32) 异常。如果您以相同的方式(使用 LockFileEx)锁定文件,可能会保护它。 【参考方案1】:

您所做的是每次将字符串写入文件末尾。为防止“占用”文件,您可以在每次写入文件时关闭该文件。

StreamWriter 的默认编码是UTF8

public static void WriteLine(string fileName, string str) 

    using (FileStream fs = new FileStream(fileName,FileMode.Append, FileAccess.Write, FileShare.Read))
    using (StreamWriter sw = new StreamWriter(fs))
    
        sw.WriteLine(str);
    

【讨论】:

我想让 FileStream 保持打开状态,因为它可能会立即需要,并且如果另一个进程打开文件会导致其他问题。要停止异常,我可以使用 FileShare.None 打开它,但肯定有一种方法可以让其他程序读取到目前为止编写的内容而不会引发任何异常? 我明白我误解了这个问题。即使您指定该文件只能由其他进程读取,它有时仍会在您的应用程序中产生冲突。看起来另一个进程正在写入。我发现了这个类似的问题:codeproject.com/Questions/122783/…(虽然没有好的答案) 确实是的:-),但实际上其他进程肯定只是读取,这仍然会导致与正在写入的应用程序中抛出的异常发生冲突!【参考方案2】:

感谢@i486 提供线索。这个版本的WriteLine似乎解决了这个问题:

    public static void WriteLine(System.IO.FileStream fileStream, string str) 
        try 
            LockFile(fileStream);
            fileStream.Seek(0, System.IO.SeekOrigin.End);
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(str + "\r\n");
            fileStream.Write(bytes, 0, bytes.Length);
            fileStream.Flush();
         finally 
            UnlockFile(fileStream);
        
    
    public static void LockFile(System.IO.FileStream fileStream) 
        bool notlocked = true;
        while (notlocked) 
            try  fileStream.Lock(0, long.MaxValue); notlocked = false;  catch (Exception Ex)  ReaperCore.CoreLogging.ExceptionDescription(Ex); 
        
    
    public static void UnlockFile(System.IO.FileStream fileStream)  fileStream.Unlock(0, long.MaxValue); 

剩下的问题是如何处理获得读取访问权限的文件保持文件锁定的可能性,因为如果发生这种情况,上面的代码将永远保留在LockFile(...) 中。

【讨论】:

以上是关于如何打开一个文件进行写入以安全地允许其他程序读取?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PHP 安全地将 JSON 数据写入文件

有关文件读取写入 和两种文件打开模式的理解

如何允许 Bob 安全地读取 /var/log/ 中的某些文件? [关闭]

如何写入/读取“设置”文本文件

如何确保在完成写入文件之前不读取文件

Java 中的 volatile int 是线程安全的吗?