Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# StreamReader ReadLine引发已处置异常而不是返回null_C#_Ftp_Stream_Streamreader_Ftpwebresponse - Fatal编程技术网

C# StreamReader ReadLine引发已处置异常而不是返回null

C# StreamReader ReadLine引发已处置异常而不是返回null,c#,ftp,stream,streamreader,ftpwebresponse,C#,Ftp,Stream,Streamreader,Ftpwebresponse,我试图从FTP服务器获取一个文本文件,然后逐行读取,将每一行添加到列表中 我的代码似乎符合以下标准模式: var response = (FtpWebResponse)request.GetResponse(); using (var responseStream = response.GetResponseStream()) { using (var reader = new StreamR

我试图从FTP服务器获取一个文本文件,然后逐行读取,将每一行添加到列表中

我的代码似乎符合以下标准模式:

            var response = (FtpWebResponse)request.GetResponse();
            using (var responseStream = response.GetResponseStream())
            {
                using (var reader = new StreamReader(responseStream))
                {
                    string line;
                    while((line = reader.ReadLine()) != null)
                    {
                        lines.Add(line);
                    }
                }
            }
但是,由于某种原因,当在文件的最后一行调用reader.ReadLine()时,它会抛出一个异常,表示“无法访问已处理的对象”

这真让我感到奇怪。如果我没记错的话,当没有更多数据时,流的最后一行是null,对吗

此外(虽然我对此不确定),这似乎只发生在当地;这项服务的实时版本似乎进展顺利(尽管有些问题我正试图弄清到底)。我的日志中当然没有看到这个问题

有人有主意吗

编辑:以下是异常的全文

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
   at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at System.Net.FtpDataStream.Read(Byte[] buffer, Int32 offset, Int32 size)
   at System.IO.StreamReader.ReadBuffer()
   at System.IO.StreamReader.ReadLine()
   at CENSORED.CatalogueJobs.Common.FtpFileManager.ReadFile(String fileName, String directory) in C:\\Projects\\CENSORED_CatalogueJobs\\CENSORED.CatalogueJobs.Common\\FtpFileManager.cs:line 104
   at CENSORED.CatalogueJobs.CENSOREDDispatchService.CENSOREDDispatchesProcess.<Process>d__12.MoveNext() in C:\\Projects\\CENSORED_CatalogueJobs\\CENSORED.CatalogueJobs.CENSOREDDispatches\\CENSOREDDispatchesProcess.cs:line 95"
编辑3:稍微宽一点的代码视图(为了我的理智暂时恢复)。这基本上就是函数中的所有内容

            var request = (FtpWebRequest)WebRequest.Create(_settings.Host + directory + fileName);

            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential(_settings.UserName, _settings.Password);
            request.UsePassive = false;
            request.UseBinary = true;

            var response = (FtpWebResponse)request.GetResponse();
            using (var responseStream = response.GetResponseStream())
            {
                using (var reader = new StreamReader(responseStream))
                {
                    string line;
                    while((line = reader.ReadLine()) != null)
                    {
                        lines.Add(line);
                    }
                }
            }

我认为正在处理的是响应流

您不应该在其周围放置
语句。流资源属于
FtpWebResponse
对象

试着移除它,看看问题是否消失

您还可以通过扩展代码来为自己和他人提供服务,以便正确地逐步完成它。它可能会揭示出其他一些东西:

using (var reader = new StreamReader(responseStream))
{
    string line = reader.ReadLine();
    while(line != null)
    {
        lines.Add(line);
        line = reader.ReadLine();
    }
}

这又是一行代码,使它更可读,更易于调试。

检查内部类的源代码表明,如果没有更多字节,它的方法将自行关闭流:

    public override int Read(byte[] buffer, int offset, int size) {
        CheckError();
        int readBytes;
        try {
            readBytes = m_NetworkStream.Read(buffer, offset, size);
        } catch {
            CheckError();
            throw;
        }
        if (readBytes == 0)
        {
            m_IsFullyRead = true;
            Close();
        }
        return readBytes;
    }
是对Dispose的直接调用:

    public virtual void Close()
    {
        /* These are correct, but we'd have to fix PipeStream & NetworkStream very carefully.
        Contract.Ensures(CanRead == false);
        Contract.Ensures(CanWrite == false);
        Contract.Ensures(CanSeek == false);
        */

        Dispose(true);
        GC.SuppressFinalize(this);
    }
这不是其他流的工作方式(如)

看起来StreamReader.ReadLine正在尝试读取更多数据,导致异常。这可能是因为它试图解码文件末尾的UTF8或UTF16字符

与其从网络流中逐行读取,不如在读取之前将其复制到内存流或文件流中

更新

这种行为虽然完全出乎意料,但也并非无理。以下是基于FTP协议本身、源代码和尝试下载多个文件的痛苦经历的更有根据的猜测

FtpWebRequest是FTP之上的一个(非常)泄漏的抽象。FTP是一种面向连接的协议,具有特定的命令,如LIST、GET和缺少的MGET。这意味着,一旦服务器完成向客户机发送数据以响应LIST或GET,它就会返回等待命令

FtpWebRequest试图通过使每个请求看起来都没有连接来隐藏这一点。这意味着,一旦客户端从响应流中读取完数据,就没有可返回的有效状态-FtpWebResponse命令不能用于发出进一步的命令。它也不能用MGET检索多个文件,这是一个很大的难题。毕竟应该只有一个响应流


随着.NET内核和使用不受支持的协议(如SFTP)的需求的增加,找到一个更好的FTP客户端库可能是一个非常好的主意。

我也遇到了这个问题。看起来FtpDataStream在关闭后将CanRead和CanWrite重置为false。因此,作为一种解决方法,您可以在阅读下一行之前检查CanRead,以避免ObjectDisposedException

using (var responseStream = response.GetResponseStream())
{
    using (var reader = new StreamReader(responseStream))
    {
        string line;
        while(responseStream.CanRead && (line = reader.ReadLine()) != null)
        {
            lines.Add(line);
        }
    }
}

如果该异常被释放,则读取器将抛出该异常,而不是在最后一行。不知何故,在某个地方您正在访问一个已处理的对象。发布完整异常,包括其调用堆栈。也许错误不在你认为的地方。您可以通过在edit:)中添加的
Exception.ToString()
Full Exception来获取调用堆栈,这表明释放的是网络流,而不是读卡器。有错误吗?您是否尝试过在
async void
或其他类型的
激发并忘记方法中阅读?进行原始调用的代码可能已经完成并在读取器有机会完成FtpWebRequest调用之前处理了响应。这表明您使用了异步代码或迭代器。我不这么认为。我将添加一个编辑,显示之前发生的其余代码。我认为,所有这些都非常基本。一旦读取器完成,处理响应流没有什么错。相反,应该始终对流使用
use
。更可能的是,
FtpWebResponse
在读者有机会阅读之前就被其他代码处理掉了finish@JuanR无论如何,StreamReader本身将关闭流,除非明确指示它保持打开状态。使用
从流中删除
不会产生任何影响effect@PanagiotisKanavos:流是由
FtpWebResponse
对象创建的,因此它有责任进行处理。当您拥有流时(例如,当您实例化流时),应始终使用
using
。@PanagiotisKanavos:Close!=我非常感谢你!回答得很好。我现在已经按照你的建议进行了重构,一切都很好。再次感谢。@MartinPrikryl
m_NetworkStream.Read
填充缓冲区数组而不关心其内容。确定。我想说的是:如果您试图通过将条件更改为
来修复此问题!reader.EndOfStream
,如果文本文件中的最后一行没有EOL字符,您仍然会得到此“已处理”异常(由
EndOfStream
引发)。
using (var responseStream = response.GetResponseStream())
{
    using (var reader = new StreamReader(responseStream))
    {
        string line;
        while(responseStream.CanRead && (line = reader.ReadLine()) != null)
        {
            lines.Add(line);
        }
    }
}