【问题标题】:Why does this code hang on reaching the first ReadLine from a StreamReader?为什么这段代码在从 StreamReader 到达第一个 ReadLine 时会挂起?
【发布时间】:2014-08-28 21:00:15
【问题描述】:

我将第一个参数中的一个大文件传递给下面的 SendXMLFile(),但由于它导致手持设备“挂起”/“冻结”,我暂时硬编码了一个小得多的文件(3 KB,而不是1121 KB) 用于测试。

该文件确实存在(与 .exe/.dll 位于同一文件夹中),如下代码所示:

// test with smaller file:
fileName = "DSD_v6666_3_20140310140737916.xml";
MessageBox.Show("Made it before file.Open");
using (FileStream fileTest = File.Open(fileName, FileMode.CreateNew)) 
{
    fileTest.Write(info, 0, info.Length);
    fileTest.Flush();
}
if (!File.Exists(fileName))
{
    MessageBox.Show(String.Format("{0} does not seem to exist", fileName));
} 
else
{
    MessageBox.Show(String.Format("{0} DOES seem to exist", fileName));
}

string justFileName = Path.GetFileNameWithoutExtension(fileName);
String uri = String.Format(@"http://SHANNON2:21609/api/inventory/sendXML/gus/woodrow/{0}", justFileName).Trim();
SendXMLFile(fileName, uri, 500);

这是随后被调用的代码,试图发送文件:

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    // TODO: Remove after testing
    String s = String.Format("xmlFilepath == {0}, uri == {1}, timeout == {2}", xmlFilepath, uri, timeout);
    MessageBox.Show(s);
    // </ TODO: Remove after testing

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

    //request.KeepAlive = false; // should this be true? <== commented out as a test, but no diff in behavior
    request.ProtocolVersion = HttpVersion.Version10;
    request.ContentType = "application/xml";
    request.Method = "POST";

    StringBuilder sb = new StringBuilder();
    // TODO: Remove after testing
    MessageBox.Show("Made it to just before the StreamReader using");
    using (StreamReader sr = new StreamReader(xmlFilepath))
    {
        // TODO: Remove after testing
        MessageBox.Show("Made it just inside the StreamReader using"); // <= This is the last point reached 
        String line;
        while ((line = sr.ReadLine()) != null)
        {
            // TODO: Remove after testing
            MessageBox.Show(string.Format("line == {0}", line));
            sb.Append("\r\n");
        }
        . . .

当我运行它时,我看到:

"Made it before file.Open"
"DSD_v6666_3_20140310140737916.xml DOES seem to exist"
[The xmlFilepath, uri, and timout vals expected]
"Made it to just before the StreamReader using"
"Made it just inside the StreamReader using"

-- 但不是“line == ...”消息 - 它挂起,我必须热启动设备才能将其从电子状态中恢复。

StreamReader 代码是否存在潜在问题,或者...???

更新

我不知道这是数据中的问题,还是我必须在代码中做出的差异才能使其在 Compact Framework 中工作。我有非常相似的代码,可以在 Winforms 应用程序中使用:

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

    request.KeepAlive = false;
    request.ProtocolVersion = HttpVersion.Version10;
    request.ContentType = "application/xml";
    request.Method = "POST";

    StringBuilder sb = new StringBuilder();
    using (StreamReader sr = new StreamReader(xmlFilepath))
    {
        String line;
        while ((line = sr.ReadLine()) != null)
        {
            sb.AppendLine(line);
        }
        byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());

        if (timeout < 0)
        {
            request.ReadWriteTimeout = timeout;
            request.Timeout = timeout;
        }

        request.ContentLength = postBytes.Length;

        try
        {
            Stream requestStream = request.GetRequestStream();

            requestStream.Write(postBytes, 0, postBytes.Length);
            requestStream.Close();

            //using (var response = (HttpWebResponse)request.GetResponse())
            //{
            //    return response.ToString();
            //}
            // alternate way, safe for older versions of .NET
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse(); 
            }
            finally
            {
                IDisposable disposableResponse = response as IDisposable;
                if (disposableResponse != null) disposableResponse.Dispose();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
            request.Abort();
            return string.Empty;
        }
    }
}

---这样调用,传递同一个文件作为测试用例:

private void button20_Click(object sender, EventArgs e)
{
    // Change the file name before each test
    String fullFilePath = @"C:\HoldingTank\DSD_v6666_3_20140310140737916.xml";
    string justFileName = Path.GetFileNameWithoutExtension(fullFilePath);
    String uri = String.Format(@"http://localhost:21608/api/inventory/sendXML/su/su/{0}", justFileName);
    SendXMLFile(fullFilePath, uri, 500);
}

更新 2

我更改了代码以使用 XMLTextReader,现在我又回到了我之前遇到的错误,即“(400) 错误请求”,其大部分血腥细节都记录在 here

这是新代码,也是我现在看到的:

public static bool WriteIt2(string fileName, string data, long fsize) { 布尔 retVal = 假; int bytRd = 0; // 如果使用这个,改变它的名字 字符串 the_Msg = "";

if (File.Exists(fileName))
{
    File.Delete(fileName);
}

Byte[] info = Encoding.UTF8.GetBytes(data);
// Testing with this relatively small file for now
fileName = "DSD_v6666_3_20140310140737916.xml";
MessageBox.Show("Made it before file.Open");
using (FileStream fileTest = File.Open(fileName, FileMode.CreateNew)) 
{
    fileTest.Write(info, 0, info.Length);
    fileTest.Flush();
}
if (!File.Exists(fileName))
{
    MessageBox.Show(String.Format("{0} does not seem to exist", fileName));
} // I have never seen the msg above, but always saw the one below, so commented it out
else //<= always exists, so unnecessary
{
    MessageBox.Show(String.Format("{0} DOES seem to exist", fileName));
}

string justFileName = Path.GetFileNameWithoutExtension(fileName);
String uri = String.Format(@"http://SHANNON2:21609/api/inventory/sendXML/su/su/{0}", justFileName).Trim();

SendXMLFile(fileName, uri, 500);

下面是实际执行读取、写入和发送(或尝试)的代码:

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    String s = String.Format("xmlFilepath == {0}, uri == {1}, timeout == {2}", xmlFilepath, uri, timeout);
    MessageBox.Show(s);
    // </ TODO: Remove after testing

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

    request.ProtocolVersion = HttpVersion.Version10;
    request.ContentType = "application/xml";
    request.Method = "POST";

    StringBuilder sb = new StringBuilder();
    MessageBox.Show("Made it to just before the StreamReader using");

    StreamReader sr = new StreamReader(xmlFilepath);
    MessageBox.Show("Made it past the StreamReader being constructed");
    XmlTextReader reader = null;    
    reader = new XmlTextReader(sr);
    while (reader.Read()) 
    {
        switch (reader.NodeType) 
        {
            case XmlNodeType.Element: // The node is an Element.
                sb.Append("<" + reader.Name);
            while (reader.MoveToNextAttribute()) // Read attributes.
                sb.Append(" " + reader.Name + "='" + reader.Value + "'");
                sb.Append(">");
                sb.Append(">");
                break;
            case XmlNodeType.Text: //Display the text in each element.
                sb.Append (reader.Value);
                break;
            case XmlNodeType. EndElement: //Display end of element.
                sb.Append("</" + reader.Name);
                sb.Append(">");
                break;
        }
    }
    // TODO: Remove after testing
    MessageBox.Show("Made it past the while loop");
    MessageBox.Show(String.Format("sb first line is {0}", sb[0].ToString()));
    MessageBox.Show(String.Format("sb tenth line is {0}", sb[9].ToString()));
    byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());

    if (timeout < 0)
    {
        request.Timeout = timeout;
    }

    request.ContentLength = postBytes.Length;

    try
    {
        Stream requestStream = request.GetRequestStream();

        requestStream.Write(postBytes, 0, postBytes.Length);
        requestStream.Close();

        // This code for older versions of .NET from ctacke:
        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse)request.GetResponse();
            return response.ToString();
        }
        finally
        {
            IDisposable disposableResponse = response as IDisposable;
            if (disposableResponse != null) disposableResponse.Dispose();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        request.Abort();
        return string.Empty;
    }
}

运行时我现在看到的内容:

0) "Made it before file.Open"
1) "DSD_v6666_3_20140310140737916.xml DOES seem to exist"
2) [ the xmlFilePath and other args - they are what is expected ]
3) "Made it to just before the StreamReader using"
4) "Made it past the StreamReader being constructed
5) "Made it past the while loop
6) "sb first line is "<"
7) "sb tenth line is ">"
8) "The remote server returned an error (400) Bad Request"

所以至少它不再挂起,但我又想知道为什么服务器认为这是一个错误的请求。

【问题讨论】:

  • 文件里面有什么吗?我怀疑它是一个空文件。
  • 踏入while时你看到了什么?
  • 知道你在开始时在那个文件中写了什么会很有趣。您能解释一下为什么使用二进制写入然后尝试使用 StreamReader.ReadLine 将其读回吗?
  • 在 while 循环之后放置另一个消息框。它可能会直接到达那里,因为line 为空(上面提到的@SriramSakthivel 为空文件)。
  • 我认为没有理由使用 XmlReader。 Reader/StringBuilder 代码可能会使 Xml 变得无效。为什么(你认为)你需要这一切?文件是一个流,请求需要一个流。完成。

标签: c# streamreader readline freeze


【解决方案1】:

我认为你应该回归基础:

public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
    using (var client = new WebClient())
    {                
        client.Headers.Add("Content-Type", "application/xml");                
        byte[] response = client.UploadFile(uri, "POST", xmlFilepath);
        return Encoding.ASCII.GetString(response);
    }
}

看看什么是有效的以及服务器对你的文件的看法。

当您确实需要 TimeOut 时,请查看 this answer

【讨论】:

  • 我尝试过这个,但它无法编译,因为 WebClient 无法被此应用程序使用的旧的精简版 .NET (Compact Framework) 识别。
  • 你仍然有请求流和 Stream.CopyTo()。
  • 即使来自测试应用程序(Winforms,.NET 4.5.1),上面的代码也不起作用;我从服务器返回 500 错误(它从那里与我的旧的、非基本的代码一起工作)。
  • 我认为你应该问一个新问题,不是关于 ReadLine,而是关于如何从 .NET compact 调用 REST 服务。提供正确的详细信息(版本等)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-16
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多